diff --git a/app/Node/NodeController.php b/app/Node/NodeController.php index bb3aa30..6e39a8f 100644 --- a/app/Node/NodeController.php +++ b/app/Node/NodeController.php @@ -8,7 +8,9 @@ use App\Node\NodeRepository; use App\Node\UseCases\BulkCreateNodes; use App\Node\UseCases\CreateNode; use App\Node\UseCases\CreateNodeRequest; +use App\Text\Text; use App\Text\TextRepository; +use App\User\User; use DomainException; use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ServerRequestInterface as Request; @@ -20,14 +22,34 @@ class NodeController private TextRepository $textRepository, ) {} - public function getNodesOfText(Response $response, int $textId): Response - { + public function getNodesOfText( + Request $request, + Response $response, + int $textId, + ): Response { + $user = $request->getAttribute('user'); + if (!$user instanceof User) { + return $this->errorResponse( + $response, + 401, + 'unauthenticated' + ); + } + $text = $this->textRepository->find($textId); if ($text === null) { return $response->withStatus(404); } + if (!$this->userMayAccessText($user, $text)) { + return $this->errorResponse( + $response, + 403, + 'forbidden' + ); + } + $nodes = $this->nodeRepository->findByTextId($textId); $data = array_map(function ($node) { @@ -47,12 +69,32 @@ class NodeController Response $response, CreateNode $createNodeUseCase, ): Response { + $user = $request->getAttribute('user'); + if (!$user instanceof User) { + return $this->errorResponse( + $response, + 401, + 'unauthenticated' + ); + } + $data = json_decode((string) $request->getBody(), true) ?? []; $textId = isset($data['textId']) ? (int) $data['textId'] : null; $title = $data['title'] ?? null; $parentNodeId = isset($data['parentNodeId']) ? (int) $data['parentNodeId'] : null; + if ($textId !== null) { + $ownershipResponse = $this->checkTextOwnership( + $user, + $textId, + $response, + ); + if ($ownershipResponse !== null) { + return $ownershipResponse; + } + } + try { $node = $createNodeUseCase->execute(new CreateNodeRequest( textId: $textId, @@ -80,6 +122,15 @@ class NodeController Response $response, BulkCreateNodes $bulkCreateNodesUseCase, ): Response { + $user = $request->getAttribute('user'); + if (!$user instanceof User) { + return $this->errorResponse( + $response, + 401, + 'unauthenticated' + ); + } + $data = json_decode((string) $request->getBody(), true) ?? []; $textId = isset($data['textId']) ? (int) $data['textId'] : null; @@ -87,6 +138,17 @@ class NodeController $titlePrefix = isset($data['titlePrefix']) ? (string) $data['titlePrefix'] : null; $count = isset($data['count']) ? (int) $data['count'] : null; + if ($textId !== null) { + $ownershipResponse = $this->checkTextOwnership( + $user, + $textId, + $response, + ); + if ($ownershipResponse !== null) { + return $ownershipResponse; + } + } + try { $nodes = $bulkCreateNodesUseCase->execute(new BulkCreateNodesRequest( textId: $textId, @@ -113,4 +175,44 @@ class NodeController $response->getBody()->write(json_encode(array_values($result))); return $response->withStatus(201)->withHeader('Content-Type', 'application/json'); } + + private function checkTextOwnership( + User $user, + int $textId, + Response $response, + ): ?Response { + $text = $this->textRepository->find($textId); + if ($text === null) { + return null; + } + if (!$this->userMayAccessText($user, $text)) { + return $this->errorResponse( + $response, + 403, + 'forbidden' + ); + } + return null; + } + + private function userMayAccessText(User $user, Text $text): bool + { + if ($user->isAdmin()) { + return true; + } + return $text->getUser()->getId() === $user->getId(); + } + + private function errorResponse( + Response $response, + int $status, + string $message, + ): Response { + $response->getBody()->write( + json_encode(['error' => $message]) + ); + + return $response->withStatus($status) + ->withHeader('Content-Type', 'application/json'); + } }