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
|
||||
|
||||
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
|
||||
// create a new document with an _id already specified. We need to
|
||||
// insert it directly into the collection
|
||||
|
@ -359,3 +373,13 @@ async function expireDeletedProject(projectId) {
|
|||
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) {
|
||||
db.projects.deleteMany({ owner_ref: ObjectId(this.id) }, callback)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue