Просмотр исходного кода

Add endpoint to delete a project

Needs acceptance tests
Simon Detheridge 6 лет назад
Родитель
Сommit
47e96a4d94

+ 5 - 0
services/filestore/app.js

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

+ 17 - 0
services/filestore/app/js/FileController.js

@@ -13,6 +13,7 @@ module.exports = {
   insertFile,
   copyFile,
   deleteFile,
+  deleteProject,
   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) {
   metrics.inc('projectSize')
   const { project_id: projectId, bucket } = req

+ 12 - 0
services/filestore/app/js/FileHandler.js

@@ -10,6 +10,7 @@ const { ConversionError, WriteError } = require('./Errors')
 module.exports = {
   insertFile: callbackify(insertFile),
   deleteFile: callbackify(deleteFile),
+  deleteProject: callbackify(deleteProject),
   getFile: callbackify(getFile),
   getFileSize: callbackify(getFileSize),
   getDirectorySize: callbackify(getDirectorySize),
@@ -17,6 +18,7 @@ module.exports = {
     getFile,
     insertFile,
     deleteFile,
+    deleteProject,
     getFileSize,
     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) {
   opts = opts || {}
   if (!opts.format && !opts.style) {

+ 8 - 0
services/filestore/app/js/KeyBuilder.js

@@ -4,6 +4,7 @@ module.exports = {
   getConvertedFolderKey,
   addCachingToKey,
   userFileKeyMiddleware,
+  userProjectKeyMiddleware,
   publicFileKeyMiddleware,
   publicProjectKeyMiddleware,
   bucketFileKeyMiddleware,
@@ -37,6 +38,13 @@ function userFileKeyMiddleware(req, res, 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) {
   if (settings.filestore.stores.public_files == null) {
     return res.status(501).send('public files not available')

+ 19 - 0
services/filestore/test/unit/js/FileControllerTests.js

@@ -40,6 +40,7 @@ describe('FileController', function() {
       getFile: sinon.stub().yields(null, fileStream),
       getFileSize: sinon.stub().yields(null, fileSize),
       deleteFile: sinon.stub().yields(),
+      deleteProject: sinon.stub().yields(),
       insertFile: sinon.stub().yields(),
       getDirectorySize: sinon.stub().yields(null, fileSize)
     }
@@ -67,6 +68,7 @@ describe('FileController', function() {
     req = {
       key: key,
       bucket: bucket,
+      project_id: projectId,
       query: {},
       params: {
         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() {
     it('should return total directory size bytes', function(done) {
       FileController.directorySize(req, {

+ 21 - 0
services/filestore/test/unit/js/FileHandlerTests.js

@@ -27,6 +27,7 @@ describe('FileHandler', function() {
   const bucket = 'my_bucket'
   const key = `${ObjectId()}/${ObjectId()}`
   const convertedFolderKey = `${ObjectId()}/${ObjectId()}`
+  const projectKey = `${ObjectId()}/`
   const sourceStream = 'sourceStream'
   const convertedKey = 'convertedKey'
   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() {
     it('should return the source stream no format or style are defined', function(done) {
       FileHandler.getFile(bucket, key, null, (err, stream) => {