aboutsummaryrefslogtreecommitdiff
path: root/lib/classes/JsonApi/Routes/Clipboards
diff options
context:
space:
mode:
authorPhilipp Schüttlöffel <schuettloeffel@zqs.uni-hannover.de>2024-09-24 10:53:31 +0200
committerPhilipp Schüttlöffel <schuettloeffel@zqs.uni-hannover.de>2024-09-24 10:53:31 +0200
commit4459dd7917f4d1c34f40bb68f0e991e9c3d53e4c (patch)
tree5c07151ae61276d334e88f6309c30d439a85c12e /lib/classes/JsonApi/Routes/Clipboards
parentda0022e5c1abbf9825ae76debaabdff7e8623bb4 (diff)
parent97a188592c679890a25c37ab78463add76a52ff7 (diff)
Merge branch 'main' into issue-3911issue-3911
Diffstat (limited to 'lib/classes/JsonApi/Routes/Clipboards')
-rw-r--r--lib/classes/JsonApi/Routes/Clipboards/Authority.php28
-rw-r--r--lib/classes/JsonApi/Routes/Clipboards/ClipboardItemsCreate.php106
-rw-r--r--lib/classes/JsonApi/Routes/Clipboards/ClipboardItemsDelete.php54
-rw-r--r--lib/classes/JsonApi/Routes/Clipboards/ClipboardItemsShow.php28
-rw-r--r--lib/classes/JsonApi/Routes/Clipboards/ClipboardsCreate.php46
-rw-r--r--lib/classes/JsonApi/Routes/Clipboards/ClipboardsDelete.php31
-rw-r--r--lib/classes/JsonApi/Routes/Clipboards/ClipboardsUpdate.php50
7 files changed, 343 insertions, 0 deletions
diff --git a/lib/classes/JsonApi/Routes/Clipboards/Authority.php b/lib/classes/JsonApi/Routes/Clipboards/Authority.php
new file mode 100644
index 0000000..5cc053a
--- /dev/null
+++ b/lib/classes/JsonApi/Routes/Clipboards/Authority.php
@@ -0,0 +1,28 @@
+<?php
+namespace JsonApi\Routes\Clipboards;
+
+use User;
+
+final class Authority
+{
+ public static function canCreateClipboard(User $user): bool
+ {
+ return true;
+ }
+
+ public static function canAccessClipboard(User $user, \Clipboard $clipboard): bool
+ {
+ return $user->id === $clipboard->user_id
+ || $user->perms === 'root';
+ }
+
+ public static function canUpdateClipboard(User $user, \Clipboard $clipboard): bool
+ {
+ return self::canAccessClipboard($user, $clipboard);
+ }
+
+ public static function canDeleteClipboard(User $user, \Clipboard $clipboard): bool
+ {
+ return self::canUpdateClipboard($user, $clipboard);
+ }
+}
diff --git a/lib/classes/JsonApi/Routes/Clipboards/ClipboardItemsCreate.php b/lib/classes/JsonApi/Routes/Clipboards/ClipboardItemsCreate.php
new file mode 100644
index 0000000..d57d0c5
--- /dev/null
+++ b/lib/classes/JsonApi/Routes/Clipboards/ClipboardItemsCreate.php
@@ -0,0 +1,106 @@
+<?php
+namespace JsonApi\Routes\Clipboards;
+
+use JsonApi\Errors\AuthorizationFailedException;
+use JsonApi\JsonApiController;
+use JsonApi\Routes\ValidationTrait;
+use JsonApi\Schemas\Clipboard;
+use Psr\Http\Message\{
+ ResponseInterface as Response,
+ ServerRequestInterface as Request
+};
+
+final class ClipboardItemsCreate extends JsonApiController
+{
+ use ValidationTrait;
+
+ public function __invoke(Request $request, Response $response, $args): Response
+ {
+ $json = $this->validate($request, $args);
+
+ $clipboard_id = $args['id'] ?? $json['data']['relationships']['clipboard']['data']['id'];
+ $clipboard = \Clipboard::find($clipboard_id);
+
+ $user = $this->getUser($request);
+ if (!Authority::canUpdateClipboard($user, $clipboard)) {
+ throw new AuthorizationFailedException();
+ }
+
+ $range_id = $json['data']['attributes']['range_id'];
+ $range_type = $json['data']['attributes']['range_type'];
+
+ $item = \ClipboardItem::findOneBySql(
+ 'clipboard_id = ? AND range_id = ? AND range_type = ?',
+ [$clipboard_id, $range_id, $range_type]
+ );
+
+ if ($item) {
+ return $this->getCodeResponse(302, [
+ 'Location' => $this->getLinkToItem($item),
+ ]);
+ }
+
+ $item = \ClipboardItem::create([
+ 'clipboard_id' => $clipboard_id,
+ 'range_id' => $range_id,
+ 'range_type' => $range_type,
+ ]);
+
+ return $this->getContentResponse($item);
+ }
+
+ protected function validateResourceDocument($json, $data)
+ {
+ $clipboardValidationError = $this->validateRequestContainsValidClipboard($json, $data);
+ if ($clipboardValidationError !== null) {
+ return $clipboardValidationError;
+ }
+
+ if (!self::arrayHas($json, 'data.attributes.range_id')) {
+ return 'No range_id defined';
+ }
+
+ if (!self::arrayHas($json, 'data.attributes.range_type')) {
+ return 'No range_type defined';
+ }
+
+ $range_type = self::arrayGet($json, 'data.attributes.range_type');
+ if (!is_a($range_type, \StudipItem::class, true)) {
+ return 'Range type must implement interface StudipItem';
+ }
+
+ return null;
+ }
+
+ private function validateRequestContainsValidClipboard($json, $data): ?string
+ {
+ if (isset($data['id'])) {
+ if (!\Clipboard::exists($data['id'])) {
+ return 'Provided clipboard id is invalid';
+ }
+ } else {
+ if (!self::arrayHas($json, 'data.relationships.clipboard')) {
+ return 'No clipboard relationship defined';
+ }
+
+ $clipboard = self::arrayGet($json, 'data.relationships.clipboard');
+ if (
+ !isset($clipboard['data']['type'], $clipboard['data']['id'])
+ || $clipboard['data']['type'] !== Clipboard::TYPE
+ ) {
+ return 'Defined clipboard relationship has invalid format.';
+ }
+ if (!\Clipboard::exists($clipboard['data']['id'])) {
+ return 'Related clipboard does not exist.';
+ }
+ }
+
+ return null;
+ }
+
+ private function getLinkToItem(\ClipboardItem $item): string
+ {
+ $json = $this->encoder->encodeData($item);
+ return json_decode($json, true)['data']['links']['self'];
+ }
+}
diff --git a/lib/classes/JsonApi/Routes/Clipboards/ClipboardItemsDelete.php b/lib/classes/JsonApi/Routes/Clipboards/ClipboardItemsDelete.php
new file mode 100644
index 0000000..a9c7cd4
--- /dev/null
+++ b/lib/classes/JsonApi/Routes/Clipboards/ClipboardItemsDelete.php
@@ -0,0 +1,54 @@
+<?php
+namespace JsonApi\Routes\Clipboards;
+
+use JsonApi\Errors\BadRequestException;
+use JsonApi\Errors\RecordNotFoundException;
+use JsonApi\JsonApiController;
+use Psr\Http\Message\{
+ ResponseInterface as Response,
+ ServerRequestInterface as Request
+};
+
+final class ClipboardItemsDelete extends JsonApiController
+{
+ protected $allowedFilteringParameters = ['range_id'];
+
+ public function __invoke(Request $request, Response $response, $args): Response
+ {
+ $clipboard = \Clipboard::find($args['id']);
+ if (!$clipboard) {
+ throw new RecordNotFoundException('Clipboard not found');
+ }
+
+ $user = $this->getUser($request);
+ if (!Authority::canUpdateClipboard($user, $clipboard)) {
+ throw new \AccessDeniedException();
+ }
+
+ $item = null;
+ if (isset($args['itemId'])) {
+ $item = \ClipboardItem::find($args['itemId']);
+ } else {
+ $filtering = iterator_to_array($this->getQueryParameters()->getFilters());
+ if (!isset($filtering['range_id'])) {
+ throw new BadRequestException('No range_id filter given');
+ }
+ $item = \ClipboardItem::findOneBySQL(
+ 'clipboard_id = ? AND range_id = ?',
+ [$clipboard->id, $filtering['range_id']]
+ );
+ }
+
+ if (!$item) {
+ throw new RecordNotFoundException('Item not found');
+ }
+
+ if ($item->clipboard_id !== $clipboard->id) {
+ throw new BadRequestException('Item does not belong to clipboard');
+ }
+
+ $item->delete();
+
+ return $this->getCodeResponse(204);
+ }
+}
diff --git a/lib/classes/JsonApi/Routes/Clipboards/ClipboardItemsShow.php b/lib/classes/JsonApi/Routes/Clipboards/ClipboardItemsShow.php
new file mode 100644
index 0000000..3c91708
--- /dev/null
+++ b/lib/classes/JsonApi/Routes/Clipboards/ClipboardItemsShow.php
@@ -0,0 +1,28 @@
+<?php
+namespace JsonApi\Routes\Clipboards;
+
+use JsonApi\Errors\AuthorizationFailedException;
+use JsonApi\Errors\RecordNotFoundException;
+use JsonApi\JsonApiController;
+use Psr\Http\Message\{
+ ResponseInterface as Response,
+ ServerRequestInterface as Request
+};
+
+final class ClipboardItemsShow extends JsonApiController
+{
+ public function __invoke(Request $request, Response $response, $args): Response
+ {
+ $item = \ClipboardItem::find($args['id']);
+ if (!$item) {
+ throw new RecordNotFoundException();
+ }
+
+ $user = $this->getUser($request);
+ if (!Authority::canAccessClipboard($user, $item->clipboard)) {
+ throw new AuthorizationFailedException();
+ }
+
+ return $this->getContentResponse($item);
+ }
+}
diff --git a/lib/classes/JsonApi/Routes/Clipboards/ClipboardsCreate.php b/lib/classes/JsonApi/Routes/Clipboards/ClipboardsCreate.php
new file mode 100644
index 0000000..57fd9b9
--- /dev/null
+++ b/lib/classes/JsonApi/Routes/Clipboards/ClipboardsCreate.php
@@ -0,0 +1,46 @@
+<?php
+namespace JsonApi\Routes\Clipboards;
+
+use JsonApi\Errors\AuthorizationFailedException;
+use JsonApi\JsonApiController;
+use JsonApi\Routes\ValidationTrait;
+use Psr\Http\Message\{
+ ResponseInterface as Response,
+ ServerRequestInterface as Request
+};
+
+final class ClipboardsCreate extends JsonApiController
+{
+ use ValidationTrait;
+
+ public function __invoke(Request $request, Response $response, $args): Response
+ {
+ $user = $this->getUser($request);
+
+ if (!Authority::canCreateClipboard($user)) {
+ throw new AuthorizationFailedException();
+ }
+
+ $json = $this->validate($request, $args);
+
+ $clipboard = \Clipboard::create([
+ 'name' => $json['data']['attributes']['name'],
+ 'user_id' => $user->id,
+ ]);
+
+ return $this->getContentResponse($clipboard);
+ }
+
+ protected function validateResourceDocument($json, $data)
+ {
+ if (!self::arrayHas($json, 'data.attributes.name')) {
+ return 'No name for the clipboard defined';
+ }
+
+ if (!trim(self::arrayGet($json, 'data.attributes.name'))) {
+ return 'Name of the clipboard may not be empty';
+ }
+
+ return null;
+ }
+}
diff --git a/lib/classes/JsonApi/Routes/Clipboards/ClipboardsDelete.php b/lib/classes/JsonApi/Routes/Clipboards/ClipboardsDelete.php
new file mode 100644
index 0000000..0897843
--- /dev/null
+++ b/lib/classes/JsonApi/Routes/Clipboards/ClipboardsDelete.php
@@ -0,0 +1,31 @@
+<?php
+namespace JsonApi\Routes\Clipboards;
+
+use JsonApi\Errors\AuthorizationFailedException;
+use JsonApi\Errors\RecordNotFoundException;
+use JsonApi\JsonApiController;
+use Psr\Http\Message\{
+ ResponseInterface as Response,
+ ServerRequestInterface as Request
+};
+
+final class ClipboardsDelete extends JsonApiController
+{
+ public function __invoke(Request $request, Response $response, $args): Response
+ {
+ $clipboard = \Clipboard::find($args['id']);
+ if (!$clipboard) {
+ throw new RecordNotFoundException();
+ }
+
+ $user = $this->getUser($request);
+
+ if (!Authority::canDeleteClipboard($user, $clipboard)) {
+ throw new AuthorizationFailedException();
+ }
+
+ $clipboard->delete();
+
+ return $this->getCodeResponse(204);
+ }
+}
diff --git a/lib/classes/JsonApi/Routes/Clipboards/ClipboardsUpdate.php b/lib/classes/JsonApi/Routes/Clipboards/ClipboardsUpdate.php
new file mode 100644
index 0000000..83d9539
--- /dev/null
+++ b/lib/classes/JsonApi/Routes/Clipboards/ClipboardsUpdate.php
@@ -0,0 +1,50 @@
+<?php
+namespace JsonApi\Routes\Clipboards;
+
+use JsonApi\Errors\AuthorizationFailedException;
+use JsonApi\Errors\RecordNotFoundException;
+use JsonApi\JsonApiController;
+use JsonApi\Routes\ValidationTrait;
+use Psr\Http\Message\{
+ ResponseInterface as Response,
+ ServerRequestInterface as Request
+};
+
+final class ClipboardsUpdate extends JsonApiController
+{
+ use ValidationTrait;
+
+ public function __invoke(Request $request, Response $response, $args): Response
+ {
+ $clipboard = \Clipboard::find($args['id']);
+ if (!$clipboard) {
+ throw new RecordNotFoundException();
+ }
+
+ $user = $this->getUser($request);
+
+ if (!Authority::canUpdateClipboard($user, $clipboard)) {
+ throw new AuthorizationFailedException();
+ }
+
+ $json = $this->validate($request, $args);
+
+ $clipboard->name = $json['data']['attributes']['name'];
+ $clipboard->store();
+
+ return $this->getContentResponse($clipboard);
+ }
+
+ protected function validateResourceDocument($json, $data)
+ {
+ if (!self::arrayHas($json, 'data.attributes.name')) {
+ return 'No name for the clipboard defined';
+ }
+
+ if (!trim(self::arrayGet($json, 'data.attributes.name'))) {
+ return 'Name of the clipboard may not be empty';
+ }
+
+ return null;
+ }
+}