mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Merge pull request #3745 from overleaf/jpa-project-restore-handle-deleted-files
[ProjectDeleter] restore project.deletedFiles into own collection GitOrigin-RevId: cb34e0e22609a49c676ebfe0753e650699b96f5d
This commit is contained in:
parent
a5637651b5
commit
f66fa58a7c
3 changed files with 110 additions and 0 deletions
|
@ -303,6 +303,20 @@ async function undeleteProject(projectId, options = {}) {
|
||||||
)
|
)
|
||||||
restored.archived = undefined
|
restored.archived = undefined
|
||||||
|
|
||||||
|
if (restored.deletedFiles && restored.deletedFiles.length > 0) {
|
||||||
|
filterDuplicateDeletedFilesInPlace(restored)
|
||||||
|
const deletedFiles = restored.deletedFiles.map(file => {
|
||||||
|
// break free from the model
|
||||||
|
file = file.toObject()
|
||||||
|
|
||||||
|
// add projectId
|
||||||
|
file.projectId = projectId
|
||||||
|
return file
|
||||||
|
})
|
||||||
|
await db.deletedFiles.insertMany(deletedFiles)
|
||||||
|
restored.deletedFiles = []
|
||||||
|
}
|
||||||
|
|
||||||
// we can't use Mongoose to re-insert the project, as it won't
|
// we can't use Mongoose to re-insert the project, as it won't
|
||||||
// create a new document with an _id already specified. We need to
|
// create a new document with an _id already specified. We need to
|
||||||
// insert it directly into the collection
|
// insert it directly into the collection
|
||||||
|
@ -359,3 +373,13 @@ async function expireDeletedProject(projectId) {
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function filterDuplicateDeletedFilesInPlace(project) {
|
||||||
|
const fileIds = new Set()
|
||||||
|
project.deletedFiles = project.deletedFiles.filter(file => {
|
||||||
|
const id = file._id.toString()
|
||||||
|
if (fileIds.has(id)) return false
|
||||||
|
fileIds.add(id)
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -362,4 +362,69 @@ describe('Deleting a project', function() {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('when the deleted project has deletedFiles', function() {
|
||||||
|
beforeEach('delete project', function(done) {
|
||||||
|
this.user.deleteProject(this.projectId, done)
|
||||||
|
})
|
||||||
|
let fileId1, fileId2
|
||||||
|
beforeEach('create files', function() {
|
||||||
|
// take a short cut and just allocate file ids
|
||||||
|
fileId1 = ObjectId()
|
||||||
|
fileId2 = ObjectId()
|
||||||
|
})
|
||||||
|
const otherFileDetails = {
|
||||||
|
name: 'universe.jpg',
|
||||||
|
linkedFileData: null,
|
||||||
|
hash: 'ed19e7d6779b47d8c63f6fa5a21954dcfb6cac00',
|
||||||
|
deletedAt: new Date()
|
||||||
|
}
|
||||||
|
beforeEach('insert deletedFiles', async function() {
|
||||||
|
const deletedFiles = [
|
||||||
|
{ _id: fileId1, ...otherFileDetails },
|
||||||
|
{ _id: fileId2, ...otherFileDetails },
|
||||||
|
// duplicate entry
|
||||||
|
{ _id: fileId1, ...otherFileDetails }
|
||||||
|
]
|
||||||
|
await db.deletedProjects.updateOne(
|
||||||
|
{ 'deleterData.deletedProjectId': ObjectId(this.projectId) },
|
||||||
|
{ $set: { 'project.deletedFiles': deletedFiles } }
|
||||||
|
)
|
||||||
|
})
|
||||||
|
describe('when undelete the project', function() {
|
||||||
|
let admin
|
||||||
|
beforeEach('create admin', function(done) {
|
||||||
|
admin = new User()
|
||||||
|
async.series(
|
||||||
|
[
|
||||||
|
cb => admin.ensureUserExists(cb),
|
||||||
|
cb => admin.ensureAdmin(cb),
|
||||||
|
cb => admin.login(cb)
|
||||||
|
],
|
||||||
|
done
|
||||||
|
)
|
||||||
|
})
|
||||||
|
beforeEach('undelete project', function(done) {
|
||||||
|
admin.undeleteProject(this.projectId, done)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should not insert deletedFiles into the projects collection', function(done) {
|
||||||
|
this.user.getProject(this.projectId, (error, project) => {
|
||||||
|
if (error) return done(error)
|
||||||
|
expect(project.deletedFiles).to.deep.equal([])
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should insert unique entries into the deletedFiles collection', async function() {
|
||||||
|
const docs = await db.deletedFiles
|
||||||
|
.find({}, { sort: { _id: 1 } })
|
||||||
|
.toArray()
|
||||||
|
expect(docs).to.deep.equal([
|
||||||
|
{ _id: fileId1, projectId: this.projectId, ...otherFileDetails },
|
||||||
|
{ _id: fileId2, projectId: this.projectId, ...otherFileDetails }
|
||||||
|
])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -356,6 +356,27 @@ class User {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
undeleteProject(projectId, callback) {
|
||||||
|
this.request.post(
|
||||||
|
{
|
||||||
|
url: `/admin/project/${projectId}/undelete`
|
||||||
|
},
|
||||||
|
(error, response) => {
|
||||||
|
if (error) {
|
||||||
|
return callback(error)
|
||||||
|
}
|
||||||
|
if (response.statusCode !== 204) {
|
||||||
|
return callback(
|
||||||
|
new Error(
|
||||||
|
`Non-success response when undeleting project: ${response.statusCode}`
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
callback(null)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
deleteProjects(callback) {
|
deleteProjects(callback) {
|
||||||
db.projects.deleteMany({ owner_ref: ObjectId(this.id) }, callback)
|
db.projects.deleteMany({ owner_ref: ObjectId(this.id) }, callback)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue