Add endpoint to delete a project

Needs acceptance tests
This commit is contained in:
Simon Detheridge 2020-03-14 14:56:29 +00:00
parent fc80aa3954
commit 47e96a4d94
6 changed files with 82 additions and 0 deletions

View file

@ -61,6 +61,11 @@ app.delete(
keyBuilder.userFileKeyMiddleware, keyBuilder.userFileKeyMiddleware,
fileController.deleteFile fileController.deleteFile
) )
app.delete(
'/project/:project_id',
keyBuilder.userProjectKeyMiddleware,
fileController.deleteProject
)
app.head( app.head(
'/template/:template_id/v/:version/:format', '/template/:template_id/v/:version/:format',

View file

@ -13,6 +13,7 @@ module.exports = {
insertFile, insertFile,
copyFile, copyFile,
deleteFile, deleteFile,
deleteProject,
directorySize directorySize
} }
@ -158,6 +159,22 @@ function deleteFile(req, res, next) {
}) })
} }
function deleteProject(req, res, next) {
metrics.inc('deleteProject')
const { project_id: projectId, bucket } = req
req.requestLogger.setMessage('getting project size')
req.requestLogger.addFields({ projectId, bucket })
FileHandler.deleteProject(bucket, projectId, function(err) {
if (err) {
next(err)
} else {
res.sendStatus(204)
}
})
}
function directorySize(req, res, next) { function directorySize(req, res, next) {
metrics.inc('projectSize') metrics.inc('projectSize')
const { project_id: projectId, bucket } = req const { project_id: projectId, bucket } = req

View file

@ -10,6 +10,7 @@ const { ConversionError, WriteError } = require('./Errors')
module.exports = { module.exports = {
insertFile: callbackify(insertFile), insertFile: callbackify(insertFile),
deleteFile: callbackify(deleteFile), deleteFile: callbackify(deleteFile),
deleteProject: callbackify(deleteProject),
getFile: callbackify(getFile), getFile: callbackify(getFile),
getFileSize: callbackify(getFileSize), getFileSize: callbackify(getFileSize),
getDirectorySize: callbackify(getDirectorySize), getDirectorySize: callbackify(getDirectorySize),
@ -17,6 +18,7 @@ module.exports = {
getFile, getFile,
insertFile, insertFile,
deleteFile, deleteFile,
deleteProject,
getFileSize, getFileSize,
getDirectorySize getDirectorySize
} }
@ -48,6 +50,16 @@ async function deleteFile(bucket, key) {
]) ])
} }
async function deleteProject(bucket, key) {
if (!key.match(/^[0-9a-f]{24}\//i)) {
throw new WriteError({
message: 'key does not match validation regex',
info: { bucket, key }
})
}
await PersistorManager.promises.deleteDirectory(bucket, key)
}
async function getFile(bucket, key, opts) { async function getFile(bucket, key, opts) {
opts = opts || {} opts = opts || {}
if (!opts.format && !opts.style) { if (!opts.format && !opts.style) {

View file

@ -4,6 +4,7 @@ module.exports = {
getConvertedFolderKey, getConvertedFolderKey,
addCachingToKey, addCachingToKey,
userFileKeyMiddleware, userFileKeyMiddleware,
userProjectKeyMiddleware,
publicFileKeyMiddleware, publicFileKeyMiddleware,
publicProjectKeyMiddleware, publicProjectKeyMiddleware,
bucketFileKeyMiddleware, bucketFileKeyMiddleware,
@ -37,6 +38,13 @@ function userFileKeyMiddleware(req, res, next) {
next() next()
} }
function userProjectKeyMiddleware(req, res, next) {
const { project_id: projectId } = req.params
req.key = `${projectId}/`
req.bucket = settings.filestore.stores.user_files
next()
}
function publicFileKeyMiddleware(req, res, next) { function publicFileKeyMiddleware(req, res, next) {
if (settings.filestore.stores.public_files == null) { if (settings.filestore.stores.public_files == null) {
return res.status(501).send('public files not available') return res.status(501).send('public files not available')

View file

@ -40,6 +40,7 @@ describe('FileController', function() {
getFile: sinon.stub().yields(null, fileStream), getFile: sinon.stub().yields(null, fileStream),
getFileSize: sinon.stub().yields(null, fileSize), getFileSize: sinon.stub().yields(null, fileSize),
deleteFile: sinon.stub().yields(), deleteFile: sinon.stub().yields(),
deleteProject: sinon.stub().yields(),
insertFile: sinon.stub().yields(), insertFile: sinon.stub().yields(),
getDirectorySize: sinon.stub().yields(null, fileSize) getDirectorySize: sinon.stub().yields(null, fileSize)
} }
@ -67,6 +68,7 @@ describe('FileController', function() {
req = { req = {
key: key, key: key,
bucket: bucket, bucket: bucket,
project_id: projectId,
query: {}, query: {},
params: { params: {
project_id: projectId, project_id: projectId,
@ -257,6 +259,23 @@ describe('FileController', function() {
}) })
}) })
describe('delete project', function() {
it('should tell the file handler', function(done) {
res.sendStatus = code => {
code.should.equal(204)
expect(FileHandler.deleteProject).to.have.been.calledWith(bucket, projectId)
done()
}
FileController.deleteProject(req, res, next)
})
it('should send a 500 if there was an error', function() {
FileHandler.deleteProject.yields(error)
FileController.deleteProject(req, res, next)
expect(next).to.have.been.calledWith(error)
})
})
describe('directorySize', function() { describe('directorySize', function() {
it('should return total directory size bytes', function(done) { it('should return total directory size bytes', function(done) {
FileController.directorySize(req, { FileController.directorySize(req, {

View file

@ -27,6 +27,7 @@ describe('FileHandler', function() {
const bucket = 'my_bucket' const bucket = 'my_bucket'
const key = `${ObjectId()}/${ObjectId()}` const key = `${ObjectId()}/${ObjectId()}`
const convertedFolderKey = `${ObjectId()}/${ObjectId()}` const convertedFolderKey = `${ObjectId()}/${ObjectId()}`
const projectKey = `${ObjectId()}/`
const sourceStream = 'sourceStream' const sourceStream = 'sourceStream'
const convertedKey = 'convertedKey' const convertedKey = 'convertedKey'
const readStream = { const readStream = {
@ -154,6 +155,26 @@ describe('FileHandler', function() {
}) })
}) })
describe('deleteProject', function() {
it('should tell the filestore manager to delete the folder', function(done) {
FileHandler.deleteProject(bucket, projectKey, err => {
expect(err).not.to.exist
expect(PersistorManager.promises.deleteDirectory).to.have.been.calledWith(
bucket,
projectKey
)
done()
})
})
it('should throw an error when the key is in the wrong format', function(done) {
FileHandler.deleteProject(bucket, 'wombat', err => {
expect(err).to.exist
done()
})
})
})
describe('getFile', function() { describe('getFile', function() {
it('should return the source stream no format or style are defined', function(done) { it('should return the source stream no format or style are defined', function(done) {
FileHandler.getFile(bucket, key, null, (err, stream) => { FileHandler.getFile(bucket, key, null, (err, stream) => {