From 06364a436719dc9b9bac68732a2fc00e584c97e1 Mon Sep 17 00:00:00 2001 From: Sami Mazouz Date: Sat, 2 Mar 2024 12:45:58 +0100 Subject: [PATCH] feat: context current endpoint helpers --- .../flags/src/Api/Resource/FlagResource.php | 6 ++-- .../src/Api/UserResourceFields.php | 2 +- .../tags/src/Api/Resource/TagResource.php | 7 ++-- framework/core/src/Api/Context.php | 35 +++++++++++++++++++ .../src/Api/Resource/AccessTokenResource.php | 2 +- .../src/Api/Resource/DiscussionResource.php | 14 ++++---- .../src/Api/Resource/NotificationResource.php | 2 +- .../core/src/Api/Resource/PostResource.php | 14 ++++---- .../core/src/Api/Resource/UserResource.php | 14 ++++---- 9 files changed, 63 insertions(+), 33 deletions(-) diff --git a/extensions/flags/src/Api/Resource/FlagResource.php b/extensions/flags/src/Api/Resource/FlagResource.php index c575664ba..726def645 100644 --- a/extensions/flags/src/Api/Resource/FlagResource.php +++ b/extensions/flags/src/Api/Resource/FlagResource.php @@ -42,7 +42,7 @@ class FlagResource extends AbstractDatabaseResource public function query(Context $context): object { - if ($context->collection instanceof self && $context->endpoint instanceof Endpoint\Index) { + if ($context->listing(self::class)) { $query = Flag::query()->groupBy('post_id'); $this->scope($query, $context); @@ -60,7 +60,7 @@ class FlagResource extends AbstractDatabaseResource public function newModel(Context $context): object { - if ($context->collection instanceof self && $context->endpoint instanceof Endpoint\Create) { + if ($context->creating(self::class)) { Flag::unguard(); return Flag::query()->firstOrNew([ @@ -118,7 +118,7 @@ class FlagResource extends AbstractDatabaseResource Schema\Relationship\ToOne::make('post') ->includable() - ->writable(fn (Flag $flag, FlarumContext $context) => $context->endpoint instanceof Endpoint\Create) + ->writable(fn (Flag $flag, FlarumContext $context) => $context->creating()) ->set(function (Flag $flag, Post $post, FlarumContext $context) { if (! ($post instanceof CommentPost)) { throw new InvalidParameterException; diff --git a/extensions/subscriptions/src/Api/UserResourceFields.php b/extensions/subscriptions/src/Api/UserResourceFields.php index ef778f7e4..f3264dc71 100644 --- a/extensions/subscriptions/src/Api/UserResourceFields.php +++ b/extensions/subscriptions/src/Api/UserResourceFields.php @@ -13,7 +13,7 @@ class UserResourceFields { return [ Schema\Str::make('subscription') - ->writable(fn (Discussion $discussion, Context $context) => $context->endpoint instanceof Endpoint\Update && ! $context->getActor()->isGuest()) + ->writable(fn (Discussion $discussion, Context $context) => $context->updating() && ! $context->getActor()->isGuest()) ->nullable() ->get(fn (Discussion $discussion) => $discussion->state?->subscription) ->set(function (Discussion $discussion, ?string $subscription, Context $context) { diff --git a/extensions/tags/src/Api/Resource/TagResource.php b/extensions/tags/src/Api/Resource/TagResource.php index 9da1aa580..033851db8 100644 --- a/extensions/tags/src/Api/Resource/TagResource.php +++ b/extensions/tags/src/Api/Resource/TagResource.php @@ -35,10 +35,7 @@ class TagResource extends AbstractDatabaseResource { $query->whereVisibleTo($context->getActor()); - if ($context->collection instanceof self && ( - $context->endpoint instanceof Endpoint\Index - || $context->endpoint instanceof Endpoint\Show - )) { + if ($context->listing(self::class) || $context->showing(self::class)) { $query->withStateFor($context->getActor()); } } @@ -143,7 +140,7 @@ class TagResource extends AbstractDatabaseResource public function saving(object $model, Context $context): ?object { - if (! $context->endpoint instanceof Endpoint\Create) { + if (! $context->creating(self::class)) { $this->events->dispatch( new Saving($model, $context->getActor(), $context->body()) ); diff --git a/framework/core/src/Api/Context.php b/framework/core/src/Api/Context.php index 5e6b44602..06a10b23b 100644 --- a/framework/core/src/Api/Context.php +++ b/framework/core/src/Api/Context.php @@ -7,13 +7,23 @@ use Flarum\Search\SearchResults; use Flarum\User\User; use Illuminate\Contracts\Container\Container; use Tobyz\JsonApiServer\Context as BaseContext; +use Tobyz\JsonApiServer\Resource\Collection; use Tobyz\JsonApiServer\Resource\Resource; class Context extends BaseContext { protected ?SearchResults $search = null; protected int|string|null $modelId = null; + + /** + * Data passed internally when reusing resource endpoint logic. + */ protected array $internal = []; + + /** + * Parameters mutated on the current instance. + * Useful for passing information between different field callbacks. + */ protected array $parameters = []; public function withModelId(int|string|null $id): static @@ -67,4 +77,29 @@ class Context extends BaseContext { return $this->parameters[$key] ?? $default; } + + public function creating(string|null $resource = null): bool + { + return $this->endpoint instanceof Endpoint\Create && (! $resource || is_a($this->collection, $resource)); + } + + public function updating(string|null $resource = null): bool + { + return $this->endpoint instanceof Endpoint\Update && (! $resource || is_a($this->collection, $resource)); + } + + public function deleting(string|null $resource = null): bool + { + return $this->endpoint instanceof Endpoint\Delete && (! $resource || is_a($this->collection, $resource)); + } + + public function showing(string|null $resource = null): bool + { + return $this->endpoint instanceof Endpoint\Show && (! $resource || is_a($this->collection, $resource)); + } + + public function listing(string|null $resource = null): bool + { + return $this->endpoint instanceof Endpoint\Index && (! $resource || is_a($this->collection, $resource)); + } } diff --git a/framework/core/src/Api/Resource/AccessTokenResource.php b/framework/core/src/Api/Resource/AccessTokenResource.php index 30827f136..bae3d82d8 100644 --- a/framework/core/src/Api/Resource/AccessTokenResource.php +++ b/framework/core/src/Api/Resource/AccessTokenResource.php @@ -41,7 +41,7 @@ class AccessTokenResource extends AbstractDatabaseResource public function newModel(\Tobyz\JsonApiServer\Context $context): object { - if ($context->endpoint instanceof Endpoint\Create && $context->collection instanceof self) { + if ($context->creating(self::class)) { $token = DeveloperAccessToken::make($context->getActor()->id); $token->last_activity_at = null; return $token; diff --git a/framework/core/src/Api/Resource/DiscussionResource.php b/framework/core/src/Api/Resource/DiscussionResource.php index 9fd47de67..362b3b52b 100644 --- a/framework/core/src/Api/Resource/DiscussionResource.php +++ b/framework/core/src/Api/Resource/DiscussionResource.php @@ -105,7 +105,7 @@ class DiscussionResource extends AbstractDatabaseResource Schema\Str::make('title') ->requiredOnCreate() ->writable(function (Discussion $discussion, Context $context) { - return $context->endpoint instanceof Endpoint\Create + return $context->creating() || $context->getActor()->can('rename', $discussion); }) ->minLength(3) @@ -145,7 +145,7 @@ class DiscussionResource extends AbstractDatabaseResource Schema\Boolean::make('isHidden') ->visible(fn (Discussion $discussion) => $discussion->hidden_at !== null) ->writable(function (Discussion $discussion, Context $context) { - return $context->endpoint instanceof Endpoint\Update + return $context->updating() && $context->getActor()->can('hide', $discussion); }) ->set(function (Discussion $discussion, bool $value, Context $context) { @@ -168,7 +168,7 @@ class DiscussionResource extends AbstractDatabaseResource return $discussion->state?->last_read_post_number; }) ->writable(function (Discussion $discussion, Context $context) { - return $context->endpoint instanceof Endpoint\Update; + return $context->updating(); }) ->set(function (Discussion $discussion, int $value, Context $context) { if ($readNumber = Arr::get($context->body(), 'data.attributes.lastReadPostNumber')) { @@ -194,11 +194,11 @@ class DiscussionResource extends AbstractDatabaseResource ->type('posts'), Schema\Relationship\ToMany::make('posts') ->withLinkage(function (Context $context) { - return $context->collection instanceof self && $context->endpoint instanceof Endpoint\Show; + return $context->showing(self::class); }) ->includable() ->get(function (Discussion $discussion, Context $context) { - $showingDiscussion = $context->collection instanceof self && $context->endpoint instanceof Endpoint\Show; + $showingDiscussion = $context->showing(self::class); if (! $showingDiscussion) { return fn () => $discussion->posts->all(); @@ -235,7 +235,7 @@ class DiscussionResource extends AbstractDatabaseResource return $allPosts; }), Schema\Relationship\ToOne::make('mostRelevantPost') - ->visible(fn (Discussion $model, Context $context) => $context->endpoint instanceof Endpoint\Index) + ->visible(fn (Discussion $model, Context $context) => $context->listing()) ->includable() ->type('posts'), Schema\Relationship\ToOne::make('hideUser') @@ -284,7 +284,7 @@ class DiscussionResource extends AbstractDatabaseResource /** @param Discussion $model */ protected function saveModel(Model $model, \Tobyz\JsonApiServer\Context $context): void { - if ($context->endpoint instanceof Endpoint\Create) { + if ($context->creating()) { $model->newQuery()->getConnection()->transaction(function () use ($model, $context) { $model->save(); diff --git a/framework/core/src/Api/Resource/NotificationResource.php b/framework/core/src/Api/Resource/NotificationResource.php index 9ea5731d9..8963ff555 100644 --- a/framework/core/src/Api/Resource/NotificationResource.php +++ b/framework/core/src/Api/Resource/NotificationResource.php @@ -33,7 +33,7 @@ class NotificationResource extends AbstractDatabaseResource public function query(\Tobyz\JsonApiServer\Context $context): object { - if ($context->collection instanceof self && $context->endpoint instanceof Endpoint\Index) { + if ($context->listing(self::class)) { /** @var Pagination $pagination */ $pagination = ($context->endpoint->paginationResolver)($context); diff --git a/framework/core/src/Api/Resource/PostResource.php b/framework/core/src/Api/Resource/PostResource.php index 83daa4c48..3b34e7658 100644 --- a/framework/core/src/Api/Resource/PostResource.php +++ b/framework/core/src/Api/Resource/PostResource.php @@ -50,7 +50,7 @@ class PostResource extends AbstractDatabaseResource public function newModel(\Tobyz\JsonApiServer\Context $context): object { - if ($context->endpoint instanceof Endpoint\Create && $context->collection instanceof self) { + if ($context->creating(self::class)) { $post = new CommentPost(); $post->user_id = $context->getActor()->id; @@ -149,7 +149,7 @@ class PostResource extends AbstractDatabaseResource Schema\Integer::make('number'), Schema\DateTime::make('createdAt') ->writable(function (Post $post, Context $context) { - return $context->endpoint instanceof Endpoint\Create + return $context->creating() && $context->getActor()->isAdmin(); }) ->default(fn () => Carbon::now()), @@ -159,9 +159,9 @@ class PostResource extends AbstractDatabaseResource Schema\Str::make('content') ->requiredOnCreate() ->writable(function (Post $post, Context $context) { - return $context->endpoint instanceof Endpoint\Create || ( + return $context->creating() || ( $post instanceof CommentPost - && $context->endpoint instanceof Endpoint\Update + && $context->updating() && $context->getActor()->can('edit', $post) ); }) @@ -172,9 +172,9 @@ class PostResource extends AbstractDatabaseResource }) ->set(function (Post $post, string $value, Context $context) { if ($post instanceof CommentPost) { - if ($context->endpoint instanceof Endpoint\Create) { + if ($context->creating()) { $post->setContentAttribute($value, $context->getActor()); - } elseif ($context->endpoint instanceof Endpoint\Update) { + } elseif ($context->updating()) { $post->revise($value, $context->getActor()); } } @@ -215,7 +215,7 @@ class PostResource extends AbstractDatabaseResource Schema\Boolean::make('isHidden') ->visible(fn (Post $post) => $post->hidden_at !== null) ->writable(function (Post $post, Context $context) { - return $context->endpoint instanceof Endpoint\Update + return $context->updating() && $context->getActor()->can('hide', $post); }) ->set(function (Post $post, bool $value, Context $context) { diff --git a/framework/core/src/Api/Resource/UserResource.php b/framework/core/src/Api/Resource/UserResource.php index 1a399edb6..48b924ef8 100644 --- a/framework/core/src/Api/Resource/UserResource.php +++ b/framework/core/src/Api/Resource/UserResource.php @@ -124,7 +124,7 @@ class UserResource extends AbstractDatabaseResource ->minLength(3) ->maxLength(30) ->writable(function (User $user, Context $context) { - return $context->endpoint instanceof Endpoint\Create + return $context->creating() || $context->getActor()->can('editCredentials', $user); }) ->set(function (User $user, string $value) { @@ -146,7 +146,7 @@ class UserResource extends AbstractDatabaseResource || $context->getActor()->id === $user->id; }) ->writable(function (User $user, Context $context) { - return $context->endpoint instanceof Endpoint\Create + return $context->creating() || $context->getActor()->can('editCredentials', $user) || $context->getActor()->id === $user->id; }) @@ -171,9 +171,7 @@ class UserResource extends AbstractDatabaseResource }) ->writable(fn (User $user, Context $context) => $context->getActor()->isAdmin()) ->set(function (User $user, $value, Context $context) { - $editing = $context->endpoint instanceof Endpoint\Update; - - if (! empty($value) && ($editing || $context->getActor()->isAdmin())) { + if (! empty($value) && ($context->updating() || $context->getActor()->isAdmin())) { $user->activate(); } }), @@ -185,7 +183,7 @@ class UserResource extends AbstractDatabaseResource ->minLength(8) ->visible(false) ->writable(function (User $user, Context $context) { - return $context->endpoint instanceof Endpoint\Create + return $context->creating() || $context->getActor()->can('editCredentials', $user); }) ->set(function (User $user, ?string $value) { @@ -195,7 +193,7 @@ class UserResource extends AbstractDatabaseResource Schema\Str::make('token') ->visible(false) ->writable(function (User $user, Context $context) { - return $context->endpoint instanceof Endpoint\Create; + return $context->creating(); }) ->set(function (User $user, ?string $value, Context $context) { if ($value) { @@ -273,7 +271,7 @@ class UserResource extends AbstractDatabaseResource }), Schema\Relationship\ToMany::make('groups') - ->writable(fn (User $user, Context $context) => $context->endpoint instanceof Endpoint\Update && $context->getActor()->can('editGroups', $user)) + ->writable(fn (User $user, Context $context) => $context->updating() && $context->getActor()->can('editGroups', $user)) ->includable() ->get(function (User $user, Context $context) { if ($context->getActor()->can('viewHiddenGroups')) {