diff --git a/tests/e2e/Controllers/BulkCreateNodesControllerTest.php b/tests/e2e/Controllers/BulkCreateNodesControllerTest.php index 660217e..2fac7e8 100644 --- a/tests/e2e/Controllers/BulkCreateNodesControllerTest.php +++ b/tests/e2e/Controllers/BulkCreateNodesControllerTest.php @@ -7,6 +7,7 @@ use App\Node\NodeController; use App\Node\UseCases\BulkCreateNodes; use App\Text\CreateTextDto; use App\User\UseCases\CreateUserDto; +use App\User\User; use App\ValueObjects\EmailAddress; use PHPUnit\Framework\TestCase; use Psr\Http\Message\ServerRequestInterface; @@ -23,19 +24,32 @@ class BulkCreateNodesControllerTest extends TestCase private FakeNodeRepository $nodeRepo; private BulkCreateNodes $useCase; private NodeController $controller; + private User $user; + private User $otherUser; + private User $admin; public function setUp(): void { $userRepo = new FakeUserRepository(); - $user = $userRepo->create(new CreateUserDto( + $this->user = $userRepo->create(new CreateUserDto( email: new EmailAddress('a@b.com'), passwordHash: '', isAdmin: false, )); + $this->otherUser = $userRepo->create(new CreateUserDto( + email: new EmailAddress('other@b.com'), + passwordHash: '', + isAdmin: false, + )); + $this->admin = $userRepo->create(new CreateUserDto( + email: new EmailAddress('admin@b.com'), + passwordHash: '', + isAdmin: true, + )); $this->textRepo = new FakeTextRepository(); $text = $this->textRepo->create(new CreateTextDto( name: 'test text', - user: $user, + user: $this->user, )); $this->nodeRepo = new FakeNodeRepository(); @@ -54,13 +68,17 @@ class BulkCreateNodesControllerTest extends TestCase ); } - private function makeRequest(array $data): ServerRequestInterface - { + private function makeRequest( + array $data, + ?User $user = null, + ): ServerRequestInterface { $body = new StreamFactory()->createStream(json_encode($data)); - return new ServerRequestFactory() + $request = new ServerRequestFactory() ->createServerRequest('POST', 'http://localhost/api/nodes/bulk') ->withHeader('Content-Type', 'application/json') ->withBody($body); + $sessionUser = $user ?? $this->user; + return $request->withAttribute('user', $sessionUser); } public function test_bulk_create_nodes_returns_201_with_created_nodes(): void @@ -227,4 +245,42 @@ class BulkCreateNodesControllerTest extends TestCase $this->assertEquals(404, $response->getStatusCode()); } + + public function test_bulk_create_nodes_returns_403_when_not_owner(): void + { + $response = $this->controller->bulkCreateNodes( + $this->makeRequest( + [ + 'textId' => 0, + 'parentNodeId' => 0, + 'titlePrefix' => 'Page', + 'count' => 3, + ], + $this->otherUser, + ), + new Response(), + $this->useCase, + ); + + $this->assertEquals(403, $response->getStatusCode()); + } + + public function test_bulk_create_nodes_allows_admin_on_any_text(): void + { + $response = $this->controller->bulkCreateNodes( + $this->makeRequest( + [ + 'textId' => 0, + 'parentNodeId' => 0, + 'titlePrefix' => 'Page', + 'count' => 2, + ], + $this->admin, + ), + new Response(), + $this->useCase, + ); + + $this->assertEquals(201, $response->getStatusCode()); + } } diff --git a/tests/e2e/Controllers/NodeControllerTest.php b/tests/e2e/Controllers/NodeControllerTest.php index c99b609..9879551 100644 --- a/tests/e2e/Controllers/NodeControllerTest.php +++ b/tests/e2e/Controllers/NodeControllerTest.php @@ -7,8 +7,10 @@ use App\Node\NodeController; use App\Node\UseCases\CreateNode; use App\Text\CreateTextDto; use App\User\UseCases\CreateUserDto; +use App\User\User; use App\ValueObjects\EmailAddress; use PHPUnit\Framework\TestCase; +use Psr\Http\Message\ServerRequestInterface; use Slim\Psr7\Factory\ServerRequestFactory; use Slim\Psr7\Factory\StreamFactory; use Slim\Psr7\Response; @@ -21,21 +23,65 @@ class NodeControllerTest extends TestCase private FakeTextRepository $textRepo; private FakeNodeRepository $nodeRepo; private NodeController $controller; + private User $user; + private User $otherUser; + private User $admin; public function setUp(): void { $userRepo = new FakeUserRepository(); - $user = $userRepo->create(new CreateUserDto( + $this->user = $userRepo->create(new CreateUserDto( email: new EmailAddress('a@b.com'), passwordHash: '', isAdmin: false, )); + $this->otherUser = $userRepo->create(new CreateUserDto( + email: new EmailAddress('other@b.com'), + passwordHash: '', + isAdmin: false, + )); + $this->admin = $userRepo->create(new CreateUserDto( + email: new EmailAddress('admin@b.com'), + passwordHash: '', + isAdmin: true, + )); $this->textRepo = new FakeTextRepository(); - $this->textRepo->create(new CreateTextDto(name: 'test text', user: $user)); + $this->textRepo->create(new CreateTextDto( + name: 'test text', + user: $this->user, + )); $this->nodeRepo = new FakeNodeRepository(); - $this->controller = new NodeController($this->nodeRepo, $this->textRepo); + $this->controller = new NodeController( + $this->nodeRepo, + $this->textRepo, + ); + } + + private function makeRequest( + array $body, + ?User $user, + ): ServerRequestInterface { + $stream = new StreamFactory()->createStream(json_encode($body)); + $request = new ServerRequestFactory() + ->createServerRequest('POST', 'http://localhost/api/nodes') + ->withHeader('Content-Type', 'application/json') + ->withBody($stream); + if ($user !== null) { + $request = $request->withAttribute('user', $user); + } + return $request; + } + + private function makeGetRequest(?User $user): ServerRequestInterface + { + $request = new ServerRequestFactory() + ->createServerRequest('GET', 'http://localhost/api/nodes/0'); + if ($user !== null) { + $request = $request->withAttribute('user', $user); + } + return $request; } public function test_get_nodes_of_text_returns_flat_array(): void @@ -47,7 +93,11 @@ class NodeControllerTest extends TestCase parentNode: null, )); - $response = $this->controller->getNodesOfText(new Response(), 0); + $response = $this->controller->getNodesOfText( + $this->makeGetRequest($this->user), + new Response(), + 0, + ); $this->assertEquals(200, $response->getStatusCode()); $this->assertEquals( @@ -60,7 +110,11 @@ class NodeControllerTest extends TestCase public function test_get_nodes_of_text_returns_empty_array_when_no_nodes(): void { - $response = $this->controller->getNodesOfText(new Response(), 0); + $response = $this->controller->getNodesOfText( + $this->makeGetRequest($this->user), + new Response(), + 0, + ); $this->assertEquals(200, $response->getStatusCode()); $this->assertEquals(json_encode([]), $response->getBody()); @@ -68,11 +122,44 @@ class NodeControllerTest extends TestCase public function test_get_nodes_of_text_returns_404_for_unknown_text(): void { - $response = $this->controller->getNodesOfText(new Response(), 99); + $response = $this->controller->getNodesOfText( + $this->makeGetRequest($this->user), + new Response(), + 99, + ); $this->assertEquals(404, $response->getStatusCode()); } + public function test_get_nodes_of_text_returns_403_when_not_owner(): void + { + $response = $this->controller->getNodesOfText( + $this->makeGetRequest($this->otherUser), + new Response(), + 0, + ); + + $this->assertEquals(403, $response->getStatusCode()); + } + + public function test_get_nodes_of_text_allows_admin(): void + { + $text = $this->textRepo->find(0); + $this->nodeRepo->create(new CreateNodeDto( + text: $text, + title: 'Root Node', + parentNode: null, + )); + + $response = $this->controller->getNodesOfText( + $this->makeGetRequest($this->admin), + new Response(), + 0, + ); + + $this->assertEquals(200, $response->getStatusCode()); + } + public function test_get_nodes_includes_parent_node_id(): void { $text = $this->textRepo->find(0); @@ -87,7 +174,11 @@ class NodeControllerTest extends TestCase parentNode: $rootNode, )); - $response = $this->controller->getNodesOfText(new Response(), 0); + $response = $this->controller->getNodesOfText( + $this->makeGetRequest($this->user), + new Response(), + 0, + ); $body = json_decode($response->getBody(), true); $this->assertEquals(0, $body[1]['parentNodeId']); @@ -102,15 +193,14 @@ class NodeControllerTest extends TestCase parentNode: null, )); - $body = new StreamFactory()->createStream(json_encode([ - 'textId' => 0, - 'title' => 'Child Node', - 'parentNodeId' => $rootNode->getId(), - ])); - $request = new ServerRequestFactory() - ->createServerRequest('POST', 'http://localhost/api/nodes') - ->withHeader('Content-Type', 'application/json') - ->withBody($body); + $request = $this->makeRequest( + [ + 'textId' => 0, + 'title' => 'Child Node', + 'parentNodeId' => $rootNode->getId(), + ], + $this->user, + ); $response = $this->controller->createNode( $request, @@ -127,14 +217,13 @@ class NodeControllerTest extends TestCase public function test_create_node_returns_400_when_title_missing(): void { - $body = new StreamFactory()->createStream(json_encode([ - 'textId' => 0, - 'parentNodeId' => null, - ])); - $request = new ServerRequestFactory() - ->createServerRequest('POST', 'http://localhost/api/nodes') - ->withHeader('Content-Type', 'application/json') - ->withBody($body); + $request = $this->makeRequest( + [ + 'textId' => 0, + 'parentNodeId' => null, + ], + $this->user, + ); $response = $this->controller->createNode( $request, @@ -147,15 +236,14 @@ class NodeControllerTest extends TestCase public function test_create_node_returns_404_when_text_not_found(): void { - $body = new StreamFactory()->createStream(json_encode([ - 'textId' => 99, - 'title' => 'Some Node', - 'parentNodeId' => null, - ])); - $request = new ServerRequestFactory() - ->createServerRequest('POST', 'http://localhost/api/nodes') - ->withHeader('Content-Type', 'application/json') - ->withBody($body); + $request = $this->makeRequest( + [ + 'textId' => 99, + 'title' => 'Some Node', + 'parentNodeId' => null, + ], + $this->user, + ); $response = $this->controller->createNode( $request, @@ -165,4 +253,44 @@ class NodeControllerTest extends TestCase $this->assertEquals(404, $response->getStatusCode()); } + + public function test_create_node_returns_403_when_not_owner(): void + { + $request = $this->makeRequest( + [ + 'textId' => 0, + 'title' => 'Hijack', + 'parentNodeId' => null, + ], + $this->otherUser, + ); + + $response = $this->controller->createNode( + $request, + new Response(), + new CreateNode($this->nodeRepo, $this->textRepo), + ); + + $this->assertEquals(403, $response->getStatusCode()); + } + + public function test_create_node_allows_admin_on_any_text(): void + { + $request = $this->makeRequest( + [ + 'textId' => 0, + 'title' => 'Admin Root', + 'parentNodeId' => null, + ], + $this->admin, + ); + + $response = $this->controller->createNode( + $request, + new Response(), + new CreateNode($this->nodeRepo, $this->textRepo), + ); + + $this->assertEquals(201, $response->getStatusCode()); + } }