diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..c3f6d4e --- /dev/null +++ b/composer.json @@ -0,0 +1,26 @@ +{ + "name": "provm/api", + "version": "1.0.0", + "type": "library", + "require": { + "psr/http-message": "*", + "slim/slim": "^4.0" + }, + "require-dev": { + "phpunit/phpunit": "*" + }, + "authors": [ + { + "name": "Aldarien", + "email": "aldarien85@gmail.com" + } + ], + "autoload": { + "psr-4": { + "ProVM\\": "src/" + } + }, + "config": { + "sort-packages": true + } +} diff --git a/src/Concept/API/Controller.php b/src/Concept/API/Controller.php new file mode 100644 index 0000000..2c9c159 --- /dev/null +++ b/src/Concept/API/Controller.php @@ -0,0 +1,17 @@ +getPlural() => $this->getService()->getAll() + ]; + return $this->withJson($response, $output); + } + public function get(ServerRequestInterface $request, ResponseInterface $response, int $id): ResponseInterface + { + $output = [ + 'id' => $id, + $this->getSingular() => $this->getService()->getById($id) + ]; + return $this->withJson($response, $output); + } + public function getMany(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface + { + $input = $request->getParsedBody(); + $output = [ + 'input' => $input, + $this->getPlural() => [] + ]; + if (isset($input[$this->getPlural()])) { + if (!is_array($input[$this->getPlural()])) { + $input[$this->getPlural()] = json_decode($input[$this->getPlural()], true); + } + foreach ($input[$this->getPlural()] as $id) { + $output[$this->getPlural()][$id] = $this->getService()->getById($id); + } + } + return $this->withJson($response, $output); + } + public function add(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface + { + $input = $request->getParsedBody(); + $output = [ + 'input' => $input, + $this->getPlural() => [] + ]; + if (isset($input[$this->getPlural()])) { + if (!is_array($input[$this->getPlural()])) { + $input[$this->getPlural()] = json_decode($input[$this->getPlural()], true); + } + foreach ($input[$this->getPlural()] as $data) { + $output[$this->getPlural()] []= $this->getService()->add($data); + } + } + return $this->withJson($response, $output); + } + public function edit(ServerRequestInterface $request, ResponseInterface $response, int $id): ResponseInterface + { + $input = $request->getParsedBody(); + $obj = $this->getService()->getById($id); + $output = [ + 'id' => $id, + 'input' => $input, + 'old' => $obj, + $this->getSingular() => $this->getService()->edit($obj, $input) + ]; + return $this->withJson($response, $output); + } + public function editMany(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface + { + $input = $request->getParsedBody(); + $output = [ + 'input' => $input, + 'old' => [], + $this->getPlural() => [] + ]; + if (isset($input[$this->getPlural()])) { + if (!is_array($input[$this->getPlural()])) { + $input[$this->getPlural()] = json_decode($input[$this->getPlural()], true); + } + foreach ($input[$this->getPlural()] as $id => $data) { + $obj = $this->getService()->getById($id); + $output['old'][$id]= $obj; + $output[$this->getPlural()][$id]= $this->getService()->edit($obj, $data); + } + } + return $this->withJson($response, $output); + } + public function delete(ServerRequestInterface $request, ResponseInterface $response, int $id): ResponseInterface + { + $obj = $this->getService()->getById($id); + $output = [ + 'id' => $id, + $this->getSingular() => $obj, + 'deleted' => $this->getService()->delete($obj) + ]; + return $this->withJson($response, $output); + } + public function deleteMany(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface + { + $input = $request->getParsedBody(); + $output = [ + 'input' => $input, + 'old' => [], + $this->getPlural() => [] + ]; + if (isset($input[$this->getPlural()])) { + if (!is_array($input[$this->getPlural()])) { + $input[$this->getPlural()] = json_decode($input[$this->getPlural()], true); + } + foreach ($input[$this->getPlural()] as $id) { + $obj = $this->getService()->getById($id); + $output['old'][$id] = $obj; + $output[$this->getPlural()][$id] = $this->getService()->delete($obj); + } + } + return $this->withJson($response, $output); + } + + abstract protected function getService(): Concept\Model\Service; + abstract protected function getSingular(): string; + abstract protected function getPlural(): string; +} diff --git a/src/Middleware/Authorization.php b/src/Middleware/Authorization.php new file mode 100644 index 0000000..d85de7e --- /dev/null +++ b/src/Middleware/Authorization.php @@ -0,0 +1,30 @@ +authorizationService->isAuthorized($request)) { + return $this->responseFactory->createResponse(403); // Forbidden + } + } catch (MissingToken $exception) { + $this->logger->alert($exception, ['request' => $request]); + return $this->responseFactory->createResponse(401); // Unathorized + } + return $handler->handle($request); + } +} \ No newline at end of file diff --git a/src/Middleware/NotFound.php b/src/Middleware/NotFound.php new file mode 100644 index 0000000..4db480d --- /dev/null +++ b/src/Middleware/NotFound.php @@ -0,0 +1,25 @@ +handle($request); + } catch (HttpNotFoundException $exception) { + $this->logger->error($exception); + $response = $this->responseFactory->createResponse(404) + ->withHeader('Content-Type', 'application/json'); + $response->getBody()->write(json_encode(['code' => 404, 'error' => 'Not Found'])); + return $response; + } + } +} diff --git a/src/Reinforce/Controller/Json.php b/src/Reinforce/Controller/Json.php new file mode 100644 index 0000000..926f2d9 --- /dev/null +++ b/src/Reinforce/Controller/Json.php @@ -0,0 +1,15 @@ +getBody()->write(json_encode($data)); + return $response + ->withStatus($statusCode) + ->withHeader('Content-Type', 'application/json'); + } +} \ No newline at end of file diff --git a/src/Service/Authorization.php b/src/Service/Authorization.php new file mode 100644 index 0000000..7b39274 --- /dev/null +++ b/src/Service/Authorization.php @@ -0,0 +1,85 @@ +getToken($request); + return ($suppliedToken === $this->token); + } + + /** + * @throws MissingToken + */ + private function getToken(ServerRequestInterface $request): string + { + try { + return $this->getHeaderToken($request); + } catch (Exception $exception) { + try { + return $this->getBodyToken($request, $exception); + } catch (Exception $exception) { + try { + return $this->getQueryToken($request, $exception); + } catch (Exception $exception) { + throw new MissingToken('request', $exception); + } + } + } + } + + /** + * @throws MissingHeader + * @throws MissingBearer + */ + private function getHeaderToken(ServerRequestInterface $request): string + { + $headers = $request->getHeader('Authorization'); + if (empty($headers)) { + throw new MissingHeader(); + } + foreach ($headers as $header) { + if (!str_starts_with($header, 'Bearer ')) { + continue; + } + return substr($header, strlen('Bearer ')); + } + throw new MissingBearer(); + } + + /** + * @throws MissingToken + */ + private function getBodyToken(ServerRequestInterface $request, Exception $previous): string + { + $body = $request->getParsedBody(); + if (empty($body['token'])) { + throw new MissingToken('body', $previous); + } + return $body['token']; + } + + /** + * @throws MissingToken + */ + private function getQueryToken(ServerRequestInterface $request, Exception $previous): string + { + $query = $request->getQueryParams(); + if (empty($query['token'])) { + throw new MissingToken('query', $previous); + } + return $query['token']; + } +} \ No newline at end of file