From 7c946ea7b298a6afe49a76d2dfb44dc643aed05f Mon Sep 17 00:00:00 2001 From: Chris Fasel Date: Fri, 2 Jul 2021 21:26:50 +0200 Subject: [PATCH 1/2] Implement delete action --- .gitignore | 3 +- src/Action/Api/Scope/Box/Delete.php | 72 +++++++++++++++++++ src/App.php | 4 +- src/Model/Input/BoxDelete.php | 45 ++++++++++++ src/ServiceProvider/Pimple.php | 6 +- tests/integration/ApiTest.php | 16 ++++- tests/integration/FrontendTest.php | 6 +- tests/src/TestCase/Integration.php | 13 +++- tests/src/TestCase/Scope.php | 9 ++- .../unit/Action/Api/Scope/Box/DeleteTest.php | 49 +++++++++++++ 10 files changed, 208 insertions(+), 15 deletions(-) create mode 100644 src/Action/Api/Scope/Box/Delete.php create mode 100644 src/Model/Input/BoxDelete.php create mode 100644 tests/unit/Action/Api/Scope/Box/DeleteTest.php diff --git a/.gitignore b/.gitignore index 05c1377..e2c247c 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ vendor/ data/ .env composer.lock -phpunit.xml \ No newline at end of file +phpunit.xml +.phpunit.result.cache diff --git a/src/Action/Api/Scope/Box/Delete.php b/src/Action/Api/Scope/Box/Delete.php new file mode 100644 index 0000000..18f6b76 --- /dev/null +++ b/src/Action/Api/Scope/Box/Delete.php @@ -0,0 +1,72 @@ +boxes = $boxes; + $this->input = $input; + $this->storagePath = $storagePath; + } + + public function __invoke(ServerRequestInterface $request) + { + /** + * The route controls these params, and they are validated so safe + * + * @var string $name + * @var string $scope + * @var string $version + * @var string $provider + */ + $params = $this->input->validate($request->getAttribute('route')->getArguments()); + if (!$params) { + return new Response\NotFound(); + } + + extract($params); + $box = $this->boxes->ofNameInScope($name, $scope); + + if ($box) { + $path = "{$this->storagePath}/{$box->path()}/{$version}/{$provider}.box"; + + if (file_exists($path) && unlink($path)) { + return new Response\Json([]); + } + } + + return new Response\NotFound(); + } +} diff --git a/src/App.php b/src/App.php index 89840d3..649826f 100644 --- a/src/App.php +++ b/src/App.php @@ -41,7 +41,7 @@ public function __construct($container = []) $this->put('/release', Action\AllClear::class); $this->group('/provider/{provider}', function () { $this->get('', Action\Api\Scope\Box\SendFile::class); - $this->delete('', Action\AllClear::class); + $this->delete('', Action\Api\Scope\Box\Delete::class); $this->get('/upload', Action\Api\Scope\Box\UploadPreFlight::class); $this->put('/upload', Action\Api\Scope\Box\Upload::class); }); @@ -63,4 +63,4 @@ public function __construct($container = []) // @formatter:on } -} \ No newline at end of file +} diff --git a/src/Model/Input/BoxDelete.php b/src/Model/Input/BoxDelete.php new file mode 100644 index 0000000..15752b5 --- /dev/null +++ b/src/Model/Input/BoxDelete.php @@ -0,0 +1,45 @@ + [$this, 'validateScope'], + 'name' => [$this, 'validateBoxName'], + 'version' => [$this, 'validateVersion'], + 'provider' => [$this, 'validateProvider'] + ]); + } + + public function validate($params) + { + return $this->perform( + $params, + [ + 'scope' => self::$SCOPE_RULE, + 'name' => self::$BOX_NAME_RULE, + 'version' => self::$VERSION_RULE, + 'provider' => ['required', 'trim', 'to_lc'] + ]); + } +} diff --git a/src/ServiceProvider/Pimple.php b/src/ServiceProvider/Pimple.php index 9705a31..58e32f6 100644 --- a/src/ServiceProvider/Pimple.php +++ b/src/ServiceProvider/Pimple.php @@ -106,6 +106,10 @@ public function register(Container $di) return new Action\Api\Scope\Box\Upload($c[Repository\Box::class], new Input\BoxUpload(), $c['path.storage']); }; + $di[Action\Api\Scope\Box\Delete::class] = function ($c) { + return new Action\Api\Scope\Box\Delete($c[Repository\Box::class], new Input\BoxDelete(), $c['path.storage']); + }; + $di[Action\Api\Scope\Box\SendFile::class] = function ($c) { return new Action\Api\Scope\Box\SendFile($c[Repository\Box::class], new Input\BoxUpload(), $c['path.storage']); }; @@ -124,4 +128,4 @@ private function resolveStoragePath() return $path; } -} \ No newline at end of file +} diff --git a/tests/integration/ApiTest.php b/tests/integration/ApiTest.php index 9c30afb..cc44440 100644 --- a/tests/integration/ApiTest.php +++ b/tests/integration/ApiTest.php @@ -67,9 +67,9 @@ public function provideGoodRoutes() // provider delete [ 'DELETE', - 'test/something/version/2.0.0/provider/test', + 'delete/test/version/1.0.0/provider/test', Response\Json::class, - null + [] ], // version release [ @@ -195,6 +195,16 @@ public function testUploadReturnsNotFound() self::assertInstanceOf(Response\NotFound::class, $response); } + public function testDeleteReturnsNotFoundOnNotExistingBox() + { + $response = $this->runApp( + 'DELETE', + '/api/v1/box/test/something/version/1.0.0/provider/virtualtest' + ); + + self::assertInstanceOf(Response\NotFound::class, $response); + } + public function testAccessTokenIsRequired() { $env = $this->fs->url() . '/.env'; @@ -258,4 +268,4 @@ public function testAccessTokenAsHeaderIsInvalid() file_put_contents($env, $old); unset($this->app); } -} \ No newline at end of file +} diff --git a/tests/integration/FrontendTest.php b/tests/integration/FrontendTest.php index 5ec0564..0c67098 100644 --- a/tests/integration/FrontendTest.php +++ b/tests/integration/FrontendTest.php @@ -36,7 +36,7 @@ public function provideGoodRoutes() return [ ['GET', '', Response\Json::class, null], ['GET', '/', Response\Json::class, null], - ['GET', '/scopes', Response\ScopeList::class, ['alt','test']], + ['GET', '/scopes', Response\ScopeList::class, ['alt', 'delete', 'test']], ['GET', '/test', Response\BoxList::class, ['username' => 'test', 'boxes' => ['test']]], ['GET', '/test/nope', Response\BoxDefinition::class, ['name' => 'test/nope', 'versions' => []]], [ @@ -65,7 +65,7 @@ public function provideGoodRoutes() ] ] ] - ] + ], ], ]; } @@ -142,4 +142,4 @@ public function testPasswordValidatesWhenSet() file_put_contents($env, $old); unset($this->app); } -} \ No newline at end of file +} diff --git a/tests/src/TestCase/Integration.php b/tests/src/TestCase/Integration.php index 0284860..8e3f870 100644 --- a/tests/src/TestCase/Integration.php +++ b/tests/src/TestCase/Integration.php @@ -37,7 +37,7 @@ abstract class Integration ], '2.0.0' => [ 'test.box' => 'test' - ] + ], ] ], "alt" => [ @@ -49,7 +49,14 @@ abstract class Integration 'vmware.box' => 'vmware' ] ] - ] + ], + 'delete' => [ + 'test' => [ + '1.0.0' => [ + 'test.box' => 'testcontent' + ] + ] + ] ] ] ]; @@ -141,4 +148,4 @@ public static function printVFS() { print_r(vfsStream::inspect(new vfsStreamStructureVisitor())->getStructure()); } -} \ No newline at end of file +} diff --git a/tests/src/TestCase/Scope.php b/tests/src/TestCase/Scope.php index 26c34c7..fe29bdd 100644 --- a/tests/src/TestCase/Scope.php +++ b/tests/src/TestCase/Scope.php @@ -44,7 +44,12 @@ abstract class Scope '1.1' => [ 'test.box' => 'test' ] - ] + ], + 'delete' => [ + '1.0.0' => [ + 'test.box' => 'testcontent' + ] + ] ] ]; @@ -56,4 +61,4 @@ protected function setUp(): void $this->fs = vfsStream::setup('scope', null, $this->scope); } -} \ No newline at end of file +} diff --git a/tests/unit/Action/Api/Scope/Box/DeleteTest.php b/tests/unit/Action/Api/Scope/Box/DeleteTest.php new file mode 100644 index 0000000..4c5daee --- /dev/null +++ b/tests/unit/Action/Api/Scope/Box/DeleteTest.php @@ -0,0 +1,49 @@ +buildRequest(); + $request->getAttribute('route') + ->setArguments( + [ + 'scope' => 'test', + 'name' => 'delete', + 'version' => '1.0.0', + 'provider' => 'test' + ]); + + // build the action itself + $action = new Delete( + new Box($this->fs->url()), + new BoxDelete(), + $this->fs->url() + ); + + // box file exists before action + self::assertTrue(file_exists($this->fs->url() . '/test/delete/1.0.0/test.box')); + + $response = $action($request); + + // file was removed + self::assertFalse(file_exists($this->fs->url() . '/test/delete/1.0.0/test.box')); + self::assertInstanceOf(Json::class, $response); + self::assertResponseHasStatus($response, 200); + + $response->getBody()->close(); + } +} From e762244aa77d347c86e6e4a916a07f6c86b6cdac Mon Sep 17 00:00:00 2001 From: Chris Fasel Date: Sat, 3 Jul 2021 12:25:13 +0200 Subject: [PATCH 2/2] Fix typo and whitespace --- src/Action/Api/Scope/Box/Delete.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Action/Api/Scope/Box/Delete.php b/src/Action/Api/Scope/Box/Delete.php index 18f6b76..df24c15 100644 --- a/src/Action/Api/Scope/Box/Delete.php +++ b/src/Action/Api/Scope/Box/Delete.php @@ -13,7 +13,7 @@ use Psr\Http\Message\ServerRequestInterface; /** - * Action for deleeting a box from the server + * Action for deleting a box from the server * * @package Phagrancy\Action\Api\Scope\Box */ @@ -36,8 +36,8 @@ class Delete public function __construct(Repository\Box $boxes, Input\BoxDelete $input, $storagePath) { - $this->boxes = $boxes; - $this->input = $input; + $this->boxes = $boxes; + $this->input = $input; $this->storagePath = $storagePath; }