mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-11-12 13:13:45 +01:00
Merge pull request #30530 from overleaf/bg-fix-zip-upload-leak
clean up temporary folder on zip upload failure GitOrigin-RevId: 83a934f41de7e4c737bb3e1123e6ac6b0cb15429
This commit is contained in:
@@ -30,38 +30,44 @@ export default {
|
|||||||
|
|
||||||
async function createProjectFromZipArchive(ownerId, defaultName, zipPath) {
|
async function createProjectFromZipArchive(ownerId, defaultName, zipPath) {
|
||||||
const contentsPath = await _extractZip(zipPath)
|
const contentsPath = await _extractZip(zipPath)
|
||||||
const { path, content } =
|
|
||||||
await ProjectRootDocManager.promises.findRootDocFileFromDirectory(
|
|
||||||
contentsPath
|
|
||||||
)
|
|
||||||
|
|
||||||
const projectName =
|
|
||||||
DocumentHelper.getTitleFromTexContent(content || '') || defaultName
|
|
||||||
const uniqueName = await _generateUniqueName(ownerId, projectName)
|
|
||||||
const project = await ProjectCreationHandler.promises.createBlankProject(
|
|
||||||
ownerId,
|
|
||||||
uniqueName
|
|
||||||
)
|
|
||||||
try {
|
try {
|
||||||
await _initializeProjectWithZipContents(ownerId, project, contentsPath)
|
const { path, content } =
|
||||||
|
await ProjectRootDocManager.promises.findRootDocFileFromDirectory(
|
||||||
if (path) {
|
contentsPath
|
||||||
await ProjectRootDocManager.promises.setRootDocFromName(project._id, path)
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
// no need to wait for the cleanup here
|
|
||||||
ProjectDeleter.promises
|
|
||||||
.deleteProject(project._id)
|
|
||||||
.catch(err =>
|
|
||||||
logger.error(
|
|
||||||
{ err, projectId: project._id },
|
|
||||||
'there was an error cleaning up project after importing a zip failed'
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
throw err
|
|
||||||
|
const projectName =
|
||||||
|
DocumentHelper.getTitleFromTexContent(content || '') || defaultName
|
||||||
|
const uniqueName = await _generateUniqueName(ownerId, projectName)
|
||||||
|
const project = await ProjectCreationHandler.promises.createBlankProject(
|
||||||
|
ownerId,
|
||||||
|
uniqueName
|
||||||
|
)
|
||||||
|
try {
|
||||||
|
await _initializeProjectWithZipContents(ownerId, project, contentsPath)
|
||||||
|
|
||||||
|
if (path) {
|
||||||
|
await ProjectRootDocManager.promises.setRootDocFromName(
|
||||||
|
project._id,
|
||||||
|
path
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
// no need to wait for the cleanup here
|
||||||
|
ProjectDeleter.promises
|
||||||
|
.deleteProject(project._id)
|
||||||
|
.catch(err =>
|
||||||
|
logger.error(
|
||||||
|
{ err, projectId: project._id },
|
||||||
|
'there was an error cleaning up project after importing a zip failed'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
return project
|
||||||
|
} finally {
|
||||||
|
await fs.promises.rm(contentsPath, { recursive: true, force: true })
|
||||||
}
|
}
|
||||||
await fs.promises.rm(contentsPath, { recursive: true, force: true })
|
|
||||||
return project
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function createProjectFromZipArchiveWithName(
|
async function createProjectFromZipArchiveWithName(
|
||||||
@@ -71,30 +77,33 @@ async function createProjectFromZipArchiveWithName(
|
|||||||
attributes = {}
|
attributes = {}
|
||||||
) {
|
) {
|
||||||
const contentsPath = await _extractZip(zipPath)
|
const contentsPath = await _extractZip(zipPath)
|
||||||
const uniqueName = await _generateUniqueName(ownerId, proposedName)
|
|
||||||
const project = await ProjectCreationHandler.promises.createBlankProject(
|
|
||||||
ownerId,
|
|
||||||
uniqueName,
|
|
||||||
attributes
|
|
||||||
)
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await _initializeProjectWithZipContents(ownerId, project, contentsPath)
|
const uniqueName = await _generateUniqueName(ownerId, proposedName)
|
||||||
await ProjectRootDocManager.promises.setRootDocAutomatically(project._id)
|
const project = await ProjectCreationHandler.promises.createBlankProject(
|
||||||
} catch (err) {
|
ownerId,
|
||||||
// no need to wait for the cleanup here
|
uniqueName,
|
||||||
ProjectDeleter.promises
|
attributes
|
||||||
.deleteProject(project._id)
|
)
|
||||||
.catch(err =>
|
|
||||||
logger.error(
|
try {
|
||||||
{ err, projectId: project._id },
|
await _initializeProjectWithZipContents(ownerId, project, contentsPath)
|
||||||
'there was an error cleaning up project after importing a zip failed'
|
await ProjectRootDocManager.promises.setRootDocAutomatically(project._id)
|
||||||
|
} catch (err) {
|
||||||
|
// no need to wait for the cleanup here
|
||||||
|
ProjectDeleter.promises
|
||||||
|
.deleteProject(project._id)
|
||||||
|
.catch(err =>
|
||||||
|
logger.error(
|
||||||
|
{ err, projectId: project._id },
|
||||||
|
'there was an error cleaning up project after importing a zip failed'
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
throw err
|
||||||
throw err
|
}
|
||||||
|
return project
|
||||||
|
} finally {
|
||||||
|
await fs.promises.rm(contentsPath, { recursive: true, force: true })
|
||||||
}
|
}
|
||||||
await fs.promises.rm(contentsPath, { recursive: true, force: true })
|
|
||||||
return project
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function _extractZip(zipPath) {
|
async function _extractZip(zipPath) {
|
||||||
@@ -102,7 +111,13 @@ async function _extractZip(zipPath) {
|
|||||||
Path.dirname(zipPath),
|
Path.dirname(zipPath),
|
||||||
`${Path.basename(zipPath, '.zip')}-${Date.now()}`
|
`${Path.basename(zipPath, '.zip')}-${Date.now()}`
|
||||||
)
|
)
|
||||||
await ArchiveManager.promises.extractZipArchive(zipPath, destination)
|
try {
|
||||||
|
await ArchiveManager.promises.extractZipArchive(zipPath, destination)
|
||||||
|
} catch (error) {
|
||||||
|
logger.debug({ zipPath, error }, 'error extracting from zip archive')
|
||||||
|
await fs.promises.rm(destination, { recursive: true, force: true })
|
||||||
|
throw error
|
||||||
|
}
|
||||||
return destination
|
return destination
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -323,6 +323,48 @@ describe('ProjectUploadManager', function () {
|
|||||||
.been.called
|
.been.called
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('when extraction fails', function () {
|
||||||
|
beforeEach(async function (ctx) {
|
||||||
|
ctx.ArchiveManager.promises.extractZipArchive.rejects(new Error('oops'))
|
||||||
|
await expect(
|
||||||
|
ctx.ProjectUploadManager.promises.createProjectFromZipArchive(
|
||||||
|
ctx.ownerId,
|
||||||
|
ctx.projectName,
|
||||||
|
ctx.zipPath
|
||||||
|
)
|
||||||
|
).to.be.rejectedWith('oops')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should remove the destination directory', function (ctx) {
|
||||||
|
ctx.fs.promises.rm.should.have.been.calledWith(ctx.extractedZipPath, {
|
||||||
|
recursive: true,
|
||||||
|
force: true,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('when project creation fails', function () {
|
||||||
|
beforeEach(async function (ctx) {
|
||||||
|
ctx.ProjectCreationHandler.promises.createBlankProject.rejects(
|
||||||
|
new Error('oops')
|
||||||
|
)
|
||||||
|
await expect(
|
||||||
|
ctx.ProjectUploadManager.promises.createProjectFromZipArchive(
|
||||||
|
ctx.ownerId,
|
||||||
|
ctx.projectName,
|
||||||
|
ctx.zipPath
|
||||||
|
)
|
||||||
|
).to.be.rejectedWith('oops')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should remove the destination directory', function (ctx) {
|
||||||
|
ctx.fs.promises.rm.should.have.been.calledWith(ctx.extractedZipPath, {
|
||||||
|
recursive: true,
|
||||||
|
force: true,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('createProjectFromZipArchiveWithName', function () {
|
describe('createProjectFromZipArchiveWithName', function () {
|
||||||
@@ -406,6 +448,13 @@ describe('ProjectUploadManager', function () {
|
|||||||
ctx.project._id
|
ctx.project._id
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should remove the destination directory', function (ctx) {
|
||||||
|
ctx.fs.promises.rm.should.have.been.calledWith(ctx.extractedZipPath, {
|
||||||
|
recursive: true,
|
||||||
|
force: true,
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('when setting automatically the root doc fails', function () {
|
describe('when setting automatically the root doc fails', function () {
|
||||||
@@ -425,6 +474,33 @@ describe('ProjectUploadManager', function () {
|
|||||||
ctx.project._id
|
ctx.project._id
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should remove the destination directory', function (ctx) {
|
||||||
|
ctx.fs.promises.rm.should.have.been.calledWith(ctx.extractedZipPath, {
|
||||||
|
recursive: true,
|
||||||
|
force: true,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('when extraction fails', function () {
|
||||||
|
beforeEach(async function (ctx) {
|
||||||
|
ctx.ArchiveManager.promises.extractZipArchive.rejects(new Error('oops'))
|
||||||
|
await expect(
|
||||||
|
ctx.ProjectUploadManager.promises.createProjectFromZipArchiveWithName(
|
||||||
|
ctx.ownerId,
|
||||||
|
ctx.projectName,
|
||||||
|
ctx.zipPath
|
||||||
|
)
|
||||||
|
).to.be.rejectedWith('oops')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should remove the destination directory', function (ctx) {
|
||||||
|
ctx.fs.promises.rm.should.have.been.calledWith(ctx.extractedZipPath, {
|
||||||
|
recursive: true,
|
||||||
|
force: true,
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user