Convert the rest of the API to new action architecture

Also make some tweaks:
- Merge SerializeAction::$include and
SerializeAction::$includeAvailable into a keyed boolean array
- Set defaults for SerializeAction::$limit and $limitMax
- Rename SerializeAction::$sortAvailable to $sortFields
This commit is contained in:
Toby Zerner 2015-05-03 12:04:43 +09:30
parent a943d5aee4
commit c750e32bfd
37 changed files with 713 additions and 551 deletions

View File

@ -2,46 +2,77 @@
use Flarum\Core\Repositories\UserRepositoryInterface; use Flarum\Core\Repositories\UserRepositoryInterface;
use Flarum\Core\Repositories\ActivityRepositoryInterface; use Flarum\Core\Repositories\ActivityRepositoryInterface;
use Flarum\Support\Actor; use Flarum\Api\Actions\SerializeCollectionAction;
use Flarum\Api\Actions\BaseAction; use Flarum\Api\JsonApiRequest;
use Flarum\Api\Actions\ApiParams; use Flarum\Api\JsonApiResponse;
use Flarum\Api\Serializers\ActivitySerializer;
class IndexAction extends BaseAction class IndexAction extends SerializeCollectionAction
{ {
/**
* @var \Flarum\Core\Repositories\UserRepositoryInterface
*/
protected $users;
/**
* @var \Flarum\Core\Repositories\ActivityRepositoryInterface
*/
protected $activity;
/**
* The name of the serializer class to output results with.
*
* @var string
*/
public static $serializer = 'Flarum\Api\Serializers\ActivitySerializer';
/**
* The relationships that are available to be included, and which ones are
* included by default.
*
* @var array
*/
public static $include = [
'sender' => true,
'post' => true,
'post.user' => true,
'post.discussion' => true,
'post.discussion.startUser' => true,
'post.discussion.lastUser' => true
];
/**
* The relations that are linked by default.
*
* @var array
*/
public static $link = ['user'];
/** /**
* Instantiate the action. * Instantiate the action.
* *
* @param \Flarum\Core\Search\Discussions\UserSearcher $searcher * @param \Flarum\Core\Repositories\UserRepositoryInterface $users
* @param \Flarum\Core\Repositories\ActivityRepositoryInterface $activity
*/ */
public function __construct(Actor $actor, UserRepositoryInterface $users, ActivityRepositoryInterface $activity) public function __construct(UserRepositoryInterface $users, ActivityRepositoryInterface $activity)
{ {
$this->actor = $actor;
$this->users = $users; $this->users = $users;
$this->activity = $activity; $this->activity = $activity;
} }
/** /**
* Show a user's activity feed. * Get the activity results, ready to be serialized and assigned to the
* document response.
* *
* @return \Illuminate\Http\Response * @param \Flarum\Api\JsonApiRequest $request
* @param \Flarum\Api\JsonApiResponse $response
* @return \Illuminate\Database\Eloquent\Collection
*/ */
protected function run(ApiParams $params) protected function data(JsonApiRequest $request, JsonApiResponse $response)
{ {
$start = $params->start(); $actor = $request->actor->getUser();
$count = $params->count(20, 50);
$type = $params->get('type');
$id = $params->get('users');
$user = $this->users->findOrFail($id, $this->actor->getUser()); $user = $this->users->findOrFail($request->get('users'), $actor);
$activity = $this->activity->findByUser($user->id, $this->actor->getUser(), $count, $start, $type); return $this->activity->findByUser($user->id, $actor, $request->limit, $request->offset, $request->get('type'));
// Finally, we can set up the activity serializer and use it to create
// a collection of activity results.
$serializer = new ActivitySerializer(['sender', 'post', 'post.discussion', 'post.user', 'post.discussion.startUser', 'post.discussion.lastUser'], ['user']);
$document = $this->document()->setData($serializer->collection($activity));
return $this->respondWithDocument($document);
} }
} }

View File

@ -32,14 +32,21 @@ class CreateAction extends BaseCreateAction
public static $serializer = 'Flarum\Api\Serializers\DiscussionSerializer'; public static $serializer = 'Flarum\Api\Serializers\DiscussionSerializer';
/** /**
* The relations that are included by default. * The relationships that are available to be included, and which ones are
* included by default.
* *
* @var array * @var array
*/ */
public static $include = ['posts', 'startUser', 'lastUser', 'startPost', 'lastPost']; public static $include = [
'posts' => true,
'startUser' => true,
'lastUser' => true,
'startPost' => true,
'lastPost' => true
];
/** /**
* Initialize the action. * Instantiate the action.
* *
* @param \Illuminate\Contracts\Bus\Dispatcher $bus * @param \Illuminate\Contracts\Bus\Dispatcher $bus
* @param \Flarum\Core\Models\Forum $forum * @param \Flarum\Core\Models\Forum $forum

View File

@ -16,7 +16,7 @@ class DeleteAction extends BaseDeleteAction
protected $bus; protected $bus;
/** /**
* Initialize the action. * Instantiate the action.
* *
* @param \Illuminate\Contracts\Bus\Dispatcher $bus * @param \Illuminate\Contracts\Bus\Dispatcher $bus
*/ */
@ -26,9 +26,10 @@ class DeleteAction extends BaseDeleteAction
} }
/** /**
* Delete a discussion according to input from the API request. * Delete a discussion.
* *
* @param \Flarum\Api\Request $request * @param \Flarum\Api\Request $request
* @param \Illuminate\Http\Response $response
* @return void * @return void
*/ */
protected function delete(Request $request, Response $response) protected function delete(Request $request, Response $response)

View File

@ -23,46 +23,25 @@ class IndexAction extends SerializeCollectionAction
public static $serializer = 'Flarum\Api\Serializers\DiscussionSerializer'; public static $serializer = 'Flarum\Api\Serializers\DiscussionSerializer';
/** /**
* The relations that are available to be included. * The relationships that are available to be included, and which ones are
* included by default.
* *
* @var array * @var array
*/ */
public static $includeAvailable = ['startUser', 'lastUser', 'startPost', 'lastPost', 'relevantPosts']; public static $include = [
'startUser' => true,
/** 'lastUser' => true,
* The relations that are included by default. 'startPost' => false,
* 'lastPost' => false,
* @var array 'relevantPosts' => false
*/ ];
public static $include = ['startUser', 'lastUser'];
/**
* The maximum number of records that can be requested.
*
* @var integer
*/
public static $limitMax = 50;
/**
* The number of records included by default.
*
* @var integer
*/
public static $limit = 20;
/** /**
* The fields that are available to be sorted by. * The fields that are available to be sorted by.
* *
* @var array * @var array
*/ */
public static $sortAvailable = ['lastTime', 'commentsCount', 'startTime']; public static $sortFields = ['lastTime', 'commentsCount', 'startTime'];
/**
* The default field to sort by.
*
* @var string
*/
public static $sort = ['lastTime' => 'desc'];
/** /**
* Instantiate the action. * Instantiate the action.

View File

@ -12,16 +12,12 @@ class ShowAction extends SerializeResourceAction
use GetsPosts; use GetsPosts;
/** /**
* The discussion repository. * @var \Flarum\Core\Repositories\DiscussionRepositoryInterface
*
* @var DiscussionRepository
*/ */
protected $discussions; protected $discussions;
/** /**
* The post repository. * @var \Flarum\Core\Repositories\PostRepositoryInterface
*
* @var PostRepository
*/ */
protected $posts; protected $posts;
@ -33,23 +29,21 @@ class ShowAction extends SerializeResourceAction
public static $serializer = 'Flarum\Api\Serializers\DiscussionSerializer'; public static $serializer = 'Flarum\Api\Serializers\DiscussionSerializer';
/** /**
* The relations that are available to be included. * The relationships that are available to be included, and which ones are
* * included by default.
* @var array
*/
public static $includeAvailable = [
'startUser', 'lastUser', 'startPost', 'lastPost', 'posts',
'posts.user', 'posts.user.groups', 'posts.editUser', 'posts.hideUser'
];
/**
* The relations that are included by default.
* *
* @var array * @var array
*/ */
public static $include = [ public static $include = [
'startPost', 'lastPost', 'posts', 'startUser' => false,
'posts.user', 'posts.user.groups', 'posts.editUser', 'posts.hideUser' 'lastUser' => false,
'startPost' => true,
'lastPost' => true,
'posts' => true,
'posts.user' => true,
'posts.user.groups' => true,
'posts.editUser' => true,
'posts.hideUser' => true
]; ];
/** /**
@ -64,33 +58,20 @@ class ShowAction extends SerializeResourceAction
* *
* @var array * @var array
*/ */
public static $sortAvailable = ['time']; public static $sortFields = ['time'];
/** /**
* The default field to sort by. * The default sort field and order to user.
* *
* @var string * @var string
*/ */
public static $sort = ['time' => 'asc']; public static $sort = ['time' => 'asc'];
/**
* The maximum number of records that can be requested.
*
* @var integer
*/
public static $limitMax = 50;
/**
* The number of records included by default.
*
* @var integer
*/
public static $limit = 20;
/** /**
* Instantiate the action. * Instantiate the action.
* *
* @param PostRepository $posts * @param \Flarum\Core\Repositories\DiscussionRepositoryInterface $discussions
* @param \Flarum\Core\Repositories\PostRepositoryInterface $posts
*/ */
public function __construct(DiscussionRepositoryInterface $discussions, PostRepositoryInterface $posts) public function __construct(DiscussionRepositoryInterface $discussions, PostRepositoryInterface $posts)
{ {

View File

@ -2,7 +2,6 @@
use Flarum\Core\Commands\EditDiscussionCommand; use Flarum\Core\Commands\EditDiscussionCommand;
use Flarum\Core\Commands\ReadDiscussionCommand; use Flarum\Core\Commands\ReadDiscussionCommand;
use Flarum\Core\Exceptions\PermissionDeniedException;
use Flarum\Api\Actions\SerializeResourceAction; use Flarum\Api\Actions\SerializeResourceAction;
use Flarum\Api\Actions\Posts\GetsPosts; use Flarum\Api\Actions\Posts\GetsPosts;
use Flarum\Api\JsonApiRequest; use Flarum\Api\JsonApiRequest;
@ -12,8 +11,6 @@ use Illuminate\Contracts\Bus\Dispatcher;
class UpdateAction extends SerializeResourceAction class UpdateAction extends SerializeResourceAction
{ {
/** /**
* The command bus.
*
* @var \Illuminate\Contracts\Bus\Dispatcher * @var \Illuminate\Contracts\Bus\Dispatcher
*/ */
protected $bus; protected $bus;
@ -30,10 +27,13 @@ class UpdateAction extends SerializeResourceAction
* *
* @var array * @var array
*/ */
public static $include = ['addedPosts', 'addedPosts.user']; public static $include = [
'addedPosts' => true,
'addedPosts.user' => true
];
/** /**
* Initialize the action. * Instantiate the action.
* *
* @param \Illuminate\Contracts\Bus\Dispatcher $bus * @param \Illuminate\Contracts\Bus\Dispatcher $bus
*/ */
@ -46,7 +46,8 @@ class UpdateAction extends SerializeResourceAction
* Update a discussion according to input from the API request, and return * Update a discussion according to input from the API request, and return
* it ready to be serialized and assigned to the JsonApi response. * it ready to be serialized and assigned to the JsonApi response.
* *
* @param \Flarum\Api\Request $request * @param \Flarum\Api\JsonApiRequest $request
* @param \Flarum\Api\JsonApiResponse $response
* @return \Flarum\Core\Models\Discussion * @return \Flarum\Core\Models\Discussion
*/ */
protected function data(JsonApiRequest $request, JsonApiResponse $response) protected function data(JsonApiRequest $request, JsonApiResponse $response)
@ -54,18 +55,12 @@ class UpdateAction extends SerializeResourceAction
$user = $request->actor->getUser(); $user = $request->actor->getUser();
$discussionId = $request->get('id'); $discussionId = $request->get('id');
// First, we will run the EditDiscussionCommand. This will update the
// discussion's direct properties; by default, this is just the title.
// As usual, however, we will fire an event to allow plugins to update
// additional properties.
if ($data = array_except($request->get('data'), ['readNumber'])) { if ($data = array_except($request->get('data'), ['readNumber'])) {
$discussion = $this->bus->dispatch( $discussion = $this->bus->dispatch(
new EditDiscussionCommand($discussionId, $user, $data) new EditDiscussionCommand($discussionId, $user, $data)
); );
} }
// Next, if a read number was specified in the request, we will run the
// ReadDiscussionCommand.
if ($readNumber = $request->get('data.readNumber')) { if ($readNumber = $request->get('data.readNumber')) {
$state = $this->bus->dispatch( $state = $this->bus->dispatch(
new ReadDiscussionCommand($discussionId, $user, $readNumber) new ReadDiscussionCommand($discussionId, $user, $readNumber)

View File

@ -1,18 +1,29 @@
<?php namespace Flarum\Api\Actions\Groups; <?php namespace Flarum\Api\Actions\Groups;
use Flarum\Core\Models\Group; use Flarum\Core\Models\Group;
use Flarum\Api\Actions\Base; use Flarum\Api\Actions\SerializeCollectionAction;
use Flarum\Api\Serializers\GroupSerializer; use Flarum\Api\JsonApiRequest;
use Flarum\Api\JsonApiResponse;
class Index extends Base class IndexAction extends SerializeCollectionAction
{ {
protected function run() /**
* The name of the serializer class to output results with.
*
* @var string
*/
public static $serializer = 'Flarum\Api\Serializers\GroupSerializer';
/**
* Get the groups, ready to be serialized and assigned to the document
* response.
*
* @param \Flarum\Api\JsonApiRequest $request
* @param \Flarum\Api\JsonApiResponse $response
* @return \Illuminate\Database\Eloquent\Collection
*/
protected function data(JsonApiRequest $request, JsonApiResponse $response)
{ {
$groups = Group::get(); return Group::get();
$serializer = new GroupSerializer;
$this->document->setData($serializer->collection($groups));
return $this->respondWithDocument();
} }
} }

View File

@ -1,50 +1,78 @@
<?php namespace Flarum\Api\Actions\Notifications; <?php namespace Flarum\Api\Actions\Notifications;
use Flarum\Core\Repositories\NotificationRepositoryInterface; use Flarum\Core\Repositories\NotificationRepositoryInterface;
use Flarum\Support\Actor;
use Flarum\Core\Exceptions\PermissionDeniedException; use Flarum\Core\Exceptions\PermissionDeniedException;
use Flarum\Api\Actions\BaseAction; use Flarum\Api\Actions\SerializeCollectionAction;
use Flarum\Api\Actions\ApiParams; use Flarum\Api\JsonApiRequest;
use Flarum\Api\Serializers\NotificationSerializer; use Flarum\Api\JsonApiResponse;
class IndexAction extends BaseAction class IndexAction extends SerializeCollectionAction
{ {
/**
* @var \Flarum\Core\Repositories\NotificationRepositoryInterface
*/
protected $notifications;
/**
* The name of the serializer class to output results with.
*
* @var string
*/
public static $serializer = 'Flarum\Api\Serializers\NotificationSerializer';
/**
* The relations that are included by default.
*
* @var array
*/
public static $include = [
'sender' => true,
'subject' => true,
'subject.discussion' => true
];
/**
* The maximum number of records that can be requested.
*
* @var integer
*/
public static $limitMax = 50;
/**
* The number of records included by default.
*
* @var integer
*/
public static $limit = 10;
/** /**
* Instantiate the action. * Instantiate the action.
* *
* @param \Flarum\Core\Search\Discussions\UserSearcher $searcher * @param \Flarum\Core\Repositories\NotificationRepositoryInterface $notifications
*/ */
public function __construct(Actor $actor, NotificationRepositoryInterface $notifications) public function __construct(NotificationRepositoryInterface $notifications)
{ {
$this->actor = $actor;
$this->notifications = $notifications; $this->notifications = $notifications;
} }
/** /**
* Show a user's notifications feed. * Get the notification results, ready to be serialized and assigned to the
* document response.
* *
* @return \Illuminate\Http\Response * @param \Flarum\Api\JsonApiRequest $request
* @param \Flarum\Api\JsonApiResponse $response
* @return \Illuminate\Database\Eloquent\Collection
*/ */
protected function run(ApiParams $params) protected function data(JsonApiRequest $request, JsonApiResponse $response)
{ {
$start = $params->start(); if (! $request->actor->isAuthenticated()) {
$count = $params->count(10, 50);
if (! $this->actor->isAuthenticated()) {
throw new PermissionDeniedException; throw new PermissionDeniedException;
} }
$user = $this->actor->getUser(); $user = $request->actor->getUser();
$notifications = $this->notifications->findByUser($user->id, $count, $start);
$user->markNotificationsAsRead()->save(); $user->markNotificationsAsRead()->save();
// Finally, we can set up the notification serializer and use it to create return $this->notifications->findByUser($user->id, $request->limit, $request->offset);
// a collection of notification results.
$serializer = new NotificationSerializer(['sender', 'subject', 'subject.discussion']);
$document = $this->document()->setData($serializer->collection($notifications));
return $this->respondWithDocument($document);
} }
} }

View File

@ -1,34 +1,47 @@
<?php namespace Flarum\Api\Actions\Notifications; <?php namespace Flarum\Api\Actions\Notifications;
use Flarum\Core\Commands\ReadNotificationCommand; use Flarum\Core\Commands\ReadNotificationCommand;
use Flarum\Api\Actions\BaseAction; use Flarum\Api\Actions\SerializeResourceAction;
use Flarum\Api\Actions\ApiParams; use Flarum\Api\JsonApiRequest;
use Flarum\Api\Serializers\NotificationSerializer; use Flarum\Api\JsonApiResponse;
use Illuminate\Contracts\Bus\Dispatcher;
class UpdateAction extends BaseAction class UpdateAction extends SerializeResourceAction
{ {
/** /**
* Edit a discussion. Allows renaming the discussion, and updating its read * @var \Illuminate\Contracts\Bus\Dispatcher
* state with regards to the current user.
*
* @return Response
*/ */
protected function run(ApiParams $params) protected $bus;
/**
* The name of the serializer class to output results with.
*
* @var string
*/
public static $serializer = 'Flarum\Api\Serializers\NotificationSerializer';
/**
* Instantiate the action.
*
* @param \Illuminate\Contracts\Bus\Dispatcher $bus
*/
public function __construct(Dispatcher $bus)
{ {
$notificationId = $params->get('id'); $this->bus = $bus;
$user = $this->actor->getUser(); }
// if ($params->get('notifications.isRead')) { /**
$command = new ReadNotificationCommand($notificationId, $user); * Mark a notification as read, and return it ready to be serialized and
$notification = $this->dispatch($command, $params); * assigned to the JsonApi response.
// } *
* @param \Flarum\Api\JsonApiRequest $request
// Presumably, the discussion was updated successfully. (One of the command * @param \Flarum\Api\JsonApiResponse $response
// handlers would have thrown an exception if not.) We set this * @return \Flarum\Core\Models\Notification
// discussion as our document's primary element. */
$serializer = new NotificationSerializer; protected function data(JsonApiRequest $request, JsonApiResponse $response)
$document = $this->document()->setData($serializer->resource($notification)); {
return $this->bus->dispatch(
return $this->respondWithDocument($document); new ReadNotificationCommand($request->get('id'), $request->actor->getUser())
);
} }
} }

View File

@ -2,46 +2,61 @@
use Flarum\Core\Commands\PostReplyCommand; use Flarum\Core\Commands\PostReplyCommand;
use Flarum\Core\Commands\ReadDiscussionCommand; use Flarum\Core\Commands\ReadDiscussionCommand;
use Flarum\Api\Actions\ApiParams; use Flarum\Api\Actions\CreateAction as BaseCreateAction;
use Flarum\Api\Actions\BaseAction; use Flarum\Api\JsonApiRequest;
use Flarum\Api\Serializers\PostSerializer; use Flarum\Api\JsonApiResponse;
use Illuminate\Contracts\Bus\Dispatcher;
class CreateAction extends BaseAction class CreateAction extends BaseCreateAction
{ {
/** /**
* Reply to a discussion. * @var \Illuminate\Contracts\Bus\Dispatcher
*
* @return Response
*/ */
protected function run(ApiParams $params) protected $bus;
/**
* The name of the serializer class to output results with.
*
* @var string
*/
public static $serializer = 'Flarum\Api\Serializers\PostSerializer';
/**
* Instantiate the action.
*
* @param \Illuminate\Contracts\Bus\Dispatcher $bus
*/
public function __construct(Dispatcher $bus)
{ {
$user = $this->actor->getUser(); $this->bus = $bus;
}
// We've received a request to post a reply. By default, the only /**
// required attributes of a post is the ID of the discussion to post in, * Reply to a discussion according to input from the API request.
// the post content, and the author's user account. Let's set up a *
// command with this information. We also fire an event to allow plugins * @param \Flarum\Api\JsonApiRequest $request
// to add data to the command. * @param \Flarum\Api\JsonApiResponse $response
$discussionId = $params->get('data.links.discussion.linkage.id'); * @return \Flarum\Core\Models\Post
$content = $params->get('data.content'); */
protected function create(JsonApiRequest $request, JsonApiResponse $response)
{
$user = $request->actor->getUser();
$command = new PostReplyCommand($discussionId, $content, $user); $discussionId = $request->get('data.links.discussion.linkage.id');
$post = $this->dispatch($command, $params);
$post = $this->bus->dispatch(
new PostReplyCommand($discussionId, $user, $request->get('data'))
);
// After replying, we assume that the user has seen all of the posts // After replying, we assume that the user has seen all of the posts
// in the discussion; thus, we will mark the discussion as read if // in the discussion; thus, we will mark the discussion as read if
// they are logged in. // they are logged in.
if ($user->exists) { if ($user->exists) {
$command = new ReadDiscussionCommand($discussionId, $user, $post->number); $this->bus->dispatch(
$this->dispatch($command, $params); new ReadDiscussionCommand($discussionId, $user, $post->number)
);
} }
// Presumably, the post was created successfully. (The command handler return $post;
// would have thrown an exception if not.) We set this post as our
// document's primary element.
$serializer = new PostSerializer;
$document = $this->document()->setData($serializer->resource($post));
return $this->respondWithDocument($document, 201);
} }
} }

View File

@ -1,23 +1,39 @@
<?php namespace Flarum\Api\Actions\Posts; <?php namespace Flarum\Api\Actions\Posts;
use Flarum\Core\Commands\DeletePostCommand; use Flarum\Core\Commands\DeletePostCommand;
use Flarum\Api\Actions\ApiParams; use Flarum\Api\Actions\DeleteAction as BaseDeleteAction;
use Flarum\Api\Actions\BaseAction; use Flarum\Api\Request;
use Illuminate\Http\Response;
use Illuminate\Contracts\Bus\Dispatcher;
class DeleteAction extends BaseAction class DeleteAction extends BaseDeleteAction
{ {
/**
* @var \Illuminate\Contracts\Bus\Dispatcher
*/
protected $bus;
/**
* Instantiate the action.
*
* @param \Illuminate\Contracts\Bus\Dispatcher $bus
*/
public function __construct(Dispatcher $bus)
{
$this->bus = $bus;
}
/** /**
* Delete a post. * Delete a post.
* *
* @return Response * @param \Flarum\Api\Request $request
* @param \Illuminate\Http\Response $response
* @return void
*/ */
protected function run(ApiParams $params) protected function delete(Request $request, Response $response)
{ {
$postId = $params->get('id'); $this->bus->dispatch(
new DeletePostCommand($request->get('id'), $request->actor->getUser())
$command = new DeletePostCommand($postId, $this->actor->getUser()); );
$this->dispatch($command, $params);
return $this->respondWithoutContent();
} }
} }

View File

@ -1,6 +1,5 @@
<?php namespace Flarum\Api\Actions\Posts; <?php namespace Flarum\Api\Actions\Posts;
use Flarum\Core\Models\User;
use Flarum\Api\JsonApiRequest; use Flarum\Api\JsonApiRequest;
trait GetsPosts trait GetsPosts

View File

@ -1,67 +1,75 @@
<?php namespace Flarum\Api\Actions\Posts; <?php namespace Flarum\Api\Actions\Posts;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Flarum\Core\Repositories\PostRepositoryInterface; use Flarum\Core\Repositories\PostRepositoryInterface;
use Flarum\Support\Actor; use Flarum\Api\Actions\SerializeCollectionAction;
use Flarum\Api\Actions\BaseAction; use Flarum\Api\JsonApiRequest;
use Flarum\Api\Actions\ApiParams; use Flarum\Api\JsonApiResponse;
use Flarum\Api\Serializers\PostSerializer;
class IndexAction extends BaseAction class IndexAction extends SerializeCollectionAction
{ {
use GetsPosts; use GetsPosts;
/** /**
* The post repository. * @var \Flarum\Core\Repositories\PostRepositoryInterface
*
* @var Post
*/ */
protected $posts; protected $posts;
/**
* The name of the serializer class to output results with.
*
* @var string
*/
public static $serializer = 'Flarum\Api\Serializers\PostSerializer';
/**
* The relationships that are available to be included, and which ones are
* included by default.
*
* @var array
*/
public static $include = [
'user' => true,
'user.groups' => true,
'editUser' => true,
'hideUser' => true,
'discussion' => true
];
/** /**
* Instantiate the action. * Instantiate the action.
* *
* @param Post $posts * @param \Flarum\Core\Repositories\PostRepositoryInterface $posts
*/ */
public function __construct(Actor $actor, PostRepositoryInterface $posts) public function __construct(PostRepositoryInterface $posts)
{ {
$this->actor = $actor;
$this->posts = $posts; $this->posts = $posts;
} }
/** /**
* Show posts from a discussion, or by providing an array of IDs. * Get the post results, ready to be serialized and assigned to the
* document response.
* *
* @return Response * @param \Flarum\Api\JsonApiRequest $request
* @param \Flarum\Api\JsonApiResponse $response
* @return \Illuminate\Database\Eloquent\Collection
*/ */
protected function run(ApiParams $params) protected function data(JsonApiRequest $request, JsonApiResponse $response)
{ {
$postIds = (array) $params->get('ids'); $postIds = (array) $request->get('ids');
$include = ['user', 'user.groups', 'editUser', 'hideUser', 'discussion']; $user = $request->actor->getUser();
$user = $this->actor->getUser();
if (count($postIds)) { if (count($postIds)) {
$posts = $this->posts->findByIds($postIds, $user); $posts = $this->posts->findByIds($postIds, $user);
} else { } else {
if ($discussionId = $params->get('discussions')) { if ($discussionId = $request->get('discussions')) {
$where['discussion_id'] = $discussionId; $where['discussion_id'] = $discussionId;
} }
if ($userId = $params->get('users')) { if ($userId = $request->get('users')) {
$where['user_id'] = $userId; $where['user_id'] = $userId;
} }
$posts = $this->getPosts($params, $where, $user); $posts = $this->getPosts($request, $where);
} }
if (! count($posts)) { return $posts;
throw new ModelNotFoundException;
}
// Finally, we can set up the post serializer and use it to create
// a post resource or collection, depending on how many posts were
// requested.
$serializer = new PostSerializer($include);
$document = $this->document()->setData($serializer->collection($posts->load($include)));
return $this->respondWithDocument($document);
} }
} }

View File

@ -2,41 +2,57 @@
use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Database\Eloquent\ModelNotFoundException;
use Flarum\Core\Repositories\PostRepositoryInterface; use Flarum\Core\Repositories\PostRepositoryInterface;
use Flarum\Support\Actor; use Flarum\Api\Actions\SerializeResourceAction;
use Flarum\Api\Actions\BaseAction; use Flarum\Api\JsonApiRequest;
use Flarum\Api\Actions\ApiParams; use Flarum\Api\JsonApiResponse;
use Flarum\Api\Serializers\PostSerializer;
class ShowAction extends BaseAction class ShowAction extends SerializeResourceAction
{ {
/**
* @var \Flarum\Core\Repositories\PostRepositoryInterface
*/
protected $posts; protected $posts;
public function __construct(Actor $actor, PostRepositoryInterface $posts) /**
* The name of the serializer class to output results with.
*
* @var string
*/
public static $serializer = 'Flarum\Api\Serializers\PostSerializer';
/**
* The relationships that are available to be included, and which ones are
* included by default.
*
* @var array
*/
public static $include = [
'user' => true,
'editUser' => true,
'hideUser' => true,
'discussion' => false
];
/**
* Instantiate the action.
*
* @param \Flarum\Core\Repositories\PostRepositoryInterface $posts
*/
public function __construct(PostRepositoryInterface $posts)
{ {
$this->actor = $actor;
$this->posts = $posts; $this->posts = $posts;
} }
/** /**
* Show a single post by ID. * Get a single post, ready to be serialized and assigned to the JsonApi
* response.
* *
* @return Response * @param \Flarum\Api\JsonApiRequest $request
* @param \Flarum\Api\JsonApiResponse $response
* @return \Flarum\Core\Models\Discussion
*/ */
protected function run(ApiParams $params) protected function data(JsonApiRequest $request, JsonApiResponse $response)
{ {
$id = $params->get('id'); return $this->posts->findOrFail($request->get('id'), $request->actor->getUser());
$posts = $this->posts->findOrFail($id, $this->actor->getUser());
$include = $params->included(['discussion', 'replyTo']);
$relations = array_merge(['user', 'editUser', 'hideUser'], $include);
$posts->load($relations);
// Finally, we can set up the post serializer and use it to create
// a post resource or collection, depending on how many posts were
// requested.
$serializer = new PostSerializer($relations);
$document = $this->document()->setData($serializer->resource($posts->first()));
return $this->respondWithDocument($document);
} }
} }

View File

@ -1,34 +1,47 @@
<?php namespace Flarum\Api\Actions\Posts; <?php namespace Flarum\Api\Actions\Posts;
use Flarum\Core\Commands\EditPostCommand; use Flarum\Core\Commands\EditPostCommand;
use Flarum\Api\Actions\ApiParams; use Flarum\Api\Actions\SerializeResourceAction;
use Flarum\Api\Actions\BaseAction; use Flarum\Api\JsonApiRequest;
use Flarum\Api\Serializers\PostSerializer; use Flarum\Api\JsonApiResponse;
use Illuminate\Contracts\Bus\Dispatcher;
class UpdateAction extends BaseAction class UpdateAction extends SerializeResourceAction
{ {
/** /**
* Edit a post. Allows revision of content, and hiding/unhiding. * @var \Illuminate\Contracts\Bus\Dispatcher
*
* @return Response
*/ */
protected function run(ApiParams $params) protected $bus;
/**
* The name of the serializer class to output results with.
*
* @var string
*/
public static $serializer = 'Flarum\Api\Serializers\PostSerializer';
/**
* Instantiate the action.
*
* @param \Illuminate\Contracts\Bus\Dispatcher $bus
*/
public function __construct(Dispatcher $bus)
{ {
$postId = $params->get('id'); $this->bus = $bus;
}
// EditPost is a single command because we don't want to allow partial /**
// updates (i.e. if we were to run one command and then another, if the * Update a post according to input from the API request, and return it
// second one failed, the first one would still have succeeded.) * ready to be serialized and assigned to the JsonApi response.
$command = new EditPostCommand($postId, $this->actor->getUser()); *
$this->hydrate($command, $params->get('data')); * @param \Flarum\Api\JsonApiRequest $request
$post = $this->dispatch($command, $params); * @param \Flarum\Api\JsonApiResponse $response
* @return \Flarum\Core\Models\Post
// Presumably, the post was updated successfully. (The command handler */
// would have thrown an exception if not.) We set this post as our protected function data(JsonApiRequest $request, JsonApiResponse $response)
// document's primary element. {
$serializer = new PostSerializer; return $this->bus->dispatch(
$document = $this->document()->setData($serializer->resource($post)); new EditPostCommand($request->get('id'), $request->actor->getUser(), $request->get('data'))
);
return $this->respondWithDocument($document);
} }
} }

View File

@ -16,21 +16,15 @@ abstract class SerializeAction implements ActionInterface
public static $serializer; public static $serializer;
/** /**
* The relations that are available to be included. * The relationships that are available to be included (keys), and which
* * ones are included by default (boolean values).
* @var array
*/
public static $includeAvailable = [];
/**
* The relations that are included by default.
* *
* @var array * @var array
*/ */
public static $include = []; public static $include = [];
/** /**
* The relations that are linked by default. * The relationships that are linked by default.
* *
* @var array * @var array
*/ */
@ -41,24 +35,24 @@ abstract class SerializeAction implements ActionInterface
* *
* @var integer * @var integer
*/ */
public static $limitMax; public static $limitMax = 50;
/** /**
* The number of records included by default. * The number of records included by default.
* *
* @var integer * @var integer
*/ */
public static $limit; public static $limit = 20;
/** /**
* The fields that are available to be sorted by. * The fields that are available to be sorted by.
* *
* @var array * @var array
*/ */
public static $sortAvailable = []; public static $sortFields = [];
/** /**
* The default field to sort by. * The default sort field and order to user.
* *
* @var string * @var string
*/ */
@ -110,7 +104,7 @@ abstract class SerializeAction implements ActionInterface
*/ */
protected static function buildJsonApiRequest(Request $request) protected static function buildJsonApiRequest(Request $request)
{ {
$request = new JsonApiRequest($request->input, $request->actor, $request->httpRequest); $request = new JsonApiRequest($request->input, $request->actor, $request->http);
$criteria = new Criteria($request->input); $criteria = new Criteria($request->input);
@ -132,7 +126,7 @@ abstract class SerializeAction implements ActionInterface
*/ */
protected static function sanitizeInclude(array $include) protected static function sanitizeInclude(array $include)
{ {
return array_intersect($include, static::$includeAvailable) ?: static::$include; return array_intersect($include, array_keys(static::$include)) ?: array_keys(array_filter(static::$include));
} }
/** /**
@ -144,7 +138,7 @@ abstract class SerializeAction implements ActionInterface
*/ */
protected static function sanitizeSort(array $sort) protected static function sanitizeSort(array $sort)
{ {
return array_intersect_key($sort, array_flip(static::$sortAvailable)) ?: static::$sort; return array_intersect_key($sort, array_flip(static::$sortFields)) ?: static::$sort;
} }
/** /**

View File

@ -1,36 +1,57 @@
<?php namespace Flarum\Api\Actions\Users; <?php namespace Flarum\Api\Actions\Users;
use Flarum\Core\Commands\RegisterUserCommand; use Flarum\Core\Commands\RegisterUserCommand;
use Flarum\Api\Actions\ApiParams; use Flarum\Api\Actions\CreateAction as BaseCreateAction;
use Flarum\Api\Actions\BaseAction; use Flarum\Api\JsonApiRequest;
use Flarum\Api\Serializers\UserSerializer; use Flarum\Api\JsonApiResponse;
use Illuminate\Contracts\Bus\Dispatcher;
class CreateAction extends BaseAction class CreateAction extends BaseCreateAction
{ {
/** /**
* Register a user. * The command bus.
* *
* @return Response * @var \Illuminate\Contracts\Bus\Dispatcher
*/ */
protected function run(ApiParams $params) protected $bus;
/**
* The default forum instance.
*
* @var \Flarum\Core\Models\Forum
*/
protected $forum;
/**
* The name of the serializer class to output results with.
*
* @var string
*/
public static $serializer = 'Flarum\Api\Serializers\UserSerializer';
/**
* Instantiate the action.
*
* @param \Illuminate\Contracts\Bus\Dispatcher $bus
* @param \Flarum\Core\Models\Forum $forum
*/
public function __construct(Dispatcher $bus, Forum $forum)
{ {
// We've received a request to register a user. By default, the only $this->bus = $bus;
// required attributes of a user is the username, email, and password. $this->forum = $forum;
// Let's set up a command with this information. We also fire an event }
// to allow plugins to add data to the command.
$username = $params->get('data.username');
$email = $params->get('data.email');
$password = $params->get('data.password');
$command = new RegisterUserCommand($username, $email, $password, $this->actor->getUser(), app('flarum.forum')); /**
$user = $this->dispatch($command, $params); * Register a user according to input from the API request.
*
// Presumably, the user was created successfully. (The command handler * @param \Flarum\Api\JsonApiRequest $request
// would have thrown an exception if not.) We set this post as our * @param \Flarum\Api\JsonApiResponse $response
// document's primary element. * @return \Flarum\Core\Models\User
$serializer = new UserSerializer; */
$document = $this->document()->setData($serializer->resource($user)); protected function create(JsonApiRequest $request, JsonApiResponse $response)
{
return $this->respondWithDocument($document, 201); return $this->bus->dispatch(
new RegisterUserCommand($request->actor->getUser(), $this->forum, $request->get('data'))
);
} }
} }

View File

@ -1,23 +1,41 @@
<?php namespace Flarum\Api\Actions\Users; <?php namespace Flarum\Api\Actions\Users;
use Flarum\Core\Commands\DeleteUserCommand; use Flarum\Core\Commands\DeleteUserCommand;
use Flarum\Api\Actions\ApiParams; use Flarum\Api\Actions\DeleteAction as BaseDeleteAction;
use Flarum\Api\Actions\BaseAction; use Flarum\Api\Request;
use Illuminate\Http\Response;
use Illuminate\Contracts\Bus\Dispatcher;
class DeleteAction extends BaseAction class DeleteAction extends BaseDeleteAction
{ {
/**
* The command bus.
*
* @var \Illuminate\Contracts\Bus\Dispatcher
*/
protected $bus;
/**
* Instantiate the action.
*
* @param \Illuminate\Contracts\Bus\Dispatcher $bus
*/
public function __construct(Dispatcher $bus)
{
$this->bus = $bus;
}
/** /**
* Delete a user. * Delete a user.
* *
* @return Response * @param \Flarum\Api\Request $request
* @param \Illuminate\Http\Response $response
* @return void
*/ */
protected function run(ApiParams $params) protected function delete(Request $request, Response $response)
{ {
$userId = $params->get('id'); $this->bus->dispatch(
new DeleteUserCommand($request->get('id'), $request->actor->getUser())
$command = new DeleteUserCommand($userId, $this->actor->getUser()); );
$this->dispatch($command, $params);
return $this->respondWithoutContent();
} }
} }

View File

@ -2,12 +2,11 @@
use Flarum\Core\Search\Users\UserSearchCriteria; use Flarum\Core\Search\Users\UserSearchCriteria;
use Flarum\Core\Search\Users\UserSearcher; use Flarum\Core\Search\Users\UserSearcher;
use Flarum\Support\Actor; use Flarum\Api\Actions\SerializeCollectionAction;
use Flarum\Api\Actions\BaseAction; use Flarum\Api\JsonApiRequest;
use Flarum\Api\Actions\ApiParams; use Flarum\Api\JsonApiResponse;
use Flarum\Api\Serializers\UserSerializer;
class IndexAction extends BaseAction class IndexAction extends SerializeCollectionAction
{ {
/** /**
* The user searcher. * The user searcher.
@ -21,59 +20,59 @@ class IndexAction extends BaseAction
* *
* @param \Flarum\Core\Search\Discussions\UserSearcher $searcher * @param \Flarum\Core\Search\Discussions\UserSearcher $searcher
*/ */
public function __construct(Actor $actor, UserSearcher $searcher) public function __construct(UserSearcher $searcher)
{ {
$this->actor = $actor;
$this->searcher = $searcher; $this->searcher = $searcher;
} }
/** /**
* Show a list of users. * The name of the serializer class to output results with.
* *
* @return \Illuminate\Http\Response * @var string
*/ */
protected function run(ApiParams $params) public static $serializer = 'Flarum\Api\Serializers\UserSerializer';
/**
* The relationships that are available to be included, and which ones are
* included by default.
*
* @var array
*/
public static $include = [
'groups' => true
];
/**
* The fields that are available to be sorted by.
*
* @var array
*/
public static $sortFields = ['username', 'postsCount', 'discussionsCount', 'lastSeenTime', 'joinTime'];
/**
* Get the user results, ready to be serialized and assigned to the
* document response.
*
* @param \Flarum\Api\JsonApiRequest $request
* @param \Flarum\Api\JsonApiResponse $response
* @return \Illuminate\Database\Eloquent\Collection
*/
protected function data(JsonApiRequest $request, JsonApiResponse $response)
{ {
$query = $params->get('q'); $criteria = new UserSearchCriteria(
$start = $params->start(); $request->actor->getUser(),
$include = $params->included(['groups']); $request->get('q'),
$count = $params->count(20, 50); $request->sort
$sort = $params->sort(['', 'username', 'posts', 'discussions', 'lastActive', 'created']); );
$relations = array_merge(['groups'], $include); $results = $this->searcher->search($criteria, $request->limit, $request->offset, $request->include);
// Set up the user searcher with our search criteria, and get the
// requested range of results with the necessary relations loaded.
$criteria = new UserSearchCriteria($this->actor->getUser(), $query, $sort['field'], $sort['order']);
$results = $this->searcher->search($criteria, $count, $start, $relations);
$document = $this->document();
if (($total = $results->getTotal()) !== null) { if (($total = $results->getTotal()) !== null) {
$document->addMeta('total', $total); $response->content->addMeta('total', $total);
} }
// If there are more results, then we need to construct a URL to the // $response->content->addMeta('moreUrl', $moreUrl);
// next results page and add that to the metadata. We do this by
// compacting all of the valid query parameters which have been
// specified.
if ($results->areMoreResults()) {
$start += $count;
$include = implode(',', $include);
$sort = $sort['string'];
$input = array_filter(compact('query', 'sort', 'start', 'count', 'include'));
$moreUrl = $this->buildUrl('users.index', [], $input);
} else {
$moreUrl = '';
}
$document->addMeta('moreUrl', $moreUrl);
// Finally, we can set up the discussion serializer and use it to create return $results->getUsers();
// a collection of discussion results.
$serializer = new UserSerializer($relations);
$document->setData($serializer->collection($results->getUsers()));
return $this->respondWithDocument($document);
} }
} }

View File

@ -1,44 +1,60 @@
<?php namespace Flarum\Api\Actions\Users; <?php namespace Flarum\Api\Actions\Users;
use Flarum\Core\Repositories\UserRepositoryInterface; use Flarum\Core\Repositories\UserRepositoryInterface;
use Flarum\Support\Actor; use Flarum\Api\Actions\SerializeResourceAction;
use Flarum\Api\Actions\ApiParams; use Flarum\Api\JsonApiRequest;
use Flarum\Api\Actions\BaseAction; use Flarum\Api\JsonApiResponse;
use Flarum\Api\Serializers\UserSerializer;
class ShowAction extends BaseAction class ShowAction extends SerializeResourceAction
{ {
protected $actor; /**
* @var \Flarum\Core\Repositories\UserRepositoryInterface
*/
protected $users; protected $users;
public function __construct(Actor $actor, UserRepositoryInterface $users) /**
* The name of the serializer class to output results with.
*
* @var string
*/
public static $serializer = 'Flarum\Api\Serializers\UserSerializer';
/**
* The relationships that are available to be included, and which ones are
* included by default.
*
* @var array
*/
public static $include = [
'groups' => true
];
/**
* Instantiate the action.
*
* @param \Flarum\Core\Repositories\UserRepositoryInterface $users
*/
public function __construct(UserRepositoryInterface $users)
{ {
$this->actor = $actor;
$this->users = $users; $this->users = $users;
} }
/** /**
* Show a single user. * Get a single user, ready to be serialized and assigned to the JsonApi
* response.
* *
* @return Response * @param \Flarum\Api\JsonApiRequest $request
* @param \Flarum\Api\JsonApiResponse $response
* @return \Flarum\Core\Models\Discussion
*/ */
public function run(ApiParams $params) protected function data(JsonApiRequest $request, JsonApiResponse $response)
{ {
$id = $params->get('id'); $id = $request->get('id');
if (! is_numeric($id)) { if (! is_numeric($id)) {
$id = $this->users->getIdForUsername($id); $id = $this->users->getIdForUsername($id);
} }
$user = $this->users->findOrFail($id, $this->actor->getUser()); return $this->users->findOrFail($id, $request->actor->getUser());
// Set up the user serializer, which we will use to create the
// document's primary resource. We will specify that we want the
// 'groups' relation to be included by default.
$serializer = new UserSerializer(['groups']);
$document = $this->document()->setData($serializer->resource($user));
return $this->respondWithDocument($document);
} }
} }

View File

@ -1,35 +1,47 @@
<?php namespace Flarum\Api\Actions\Users; <?php namespace Flarum\Api\Actions\Users;
use Flarum\Core\Commands\EditUserCommand; use Flarum\Core\Commands\EditUserCommand;
use Flarum\Api\Actions\ApiParams; use Flarum\Api\Actions\SerializeResourceAction;
use Flarum\Api\Actions\BaseAction; use Flarum\Api\JsonApiRequest;
use Flarum\Api\Serializers\UserSerializer; use Flarum\Api\JsonApiResponse;
use Illuminate\Contracts\Bus\Dispatcher;
class UpdateAction extends BaseAction class UpdateAction extends SerializeResourceAction
{ {
/** /**
* Edit a user. Allows renaming the user, changing their email, and setting * @var \Illuminate\Contracts\Bus\Dispatcher
* their password.
*
* @return Response
*/ */
protected function run(ApiParams $params) protected $bus;
/**
* The name of the serializer class to output results with.
*
* @var string
*/
public static $serializer = 'Flarum\Api\Serializers\UserSerializer';
/**
* Instantiate the action.
*
* @param \Illuminate\Contracts\Bus\Dispatcher $bus
*/
public function __construct(Dispatcher $bus)
{ {
$userId = $params->get('id'); $this->bus = $bus;
}
// EditUser is a single command because we don't want to allow partial /**
// updates (i.e. if we were to run one command and then another, if the * Update a user according to input from the API request, and return it
// second one failed, the first one would still have succeeded.) * ready to be serialized and assigned to the JsonApi response.
$command = new EditUserCommand($userId, $this->actor->getUser()); *
$this->hydrate($command, $params->get('data')); * @param \Flarum\Api\JsonApiRequest $request
$user = $this->dispatch($command, $params); * @param \Flarum\Api\JsonApiResponse $response
* @return \Flarum\Core\Models\Post
// Presumably, the user was updated successfully. (The command handler */
// would have thrown an exception if not.) We set this user as our protected function data(JsonApiRequest $request, JsonApiResponse $response)
// document's primary element. {
$serializer = new UserSerializer; return $this->bus->dispatch(
$document = $this->document()->setData($serializer->resource($user)); new EditUserCommand($request->get('id'), $request->actor->getUser(), $request->get('data'))
);
return $this->respondWithDocument($document);
} }
} }

View File

@ -1,25 +1,47 @@
<?php namespace Flarum\Api\Actions\Users; <?php namespace Flarum\Api\Actions\Users;
use Flarum\Api\Actions\BaseAction;
use Flarum\Core\Commands\UploadAvatarCommand; use Flarum\Core\Commands\UploadAvatarCommand;
use Flarum\Api\Serializers\UserSerializer; use Flarum\Api\Actions\SerializeResourceAction;
use Illuminate\Http\Request; use Flarum\Api\JsonApiRequest;
use Flarum\Api\JsonApiResponse;
use Illuminate\Contracts\Bus\Dispatcher;
class UploadAvatarAction extends BaseAction class UploadAvatarAction extends SerializeResourceAction
{ {
public function handle(Request $request, $routeParams = []) /**
* @var \Illuminate\Contracts\Bus\Dispatcher
*/
protected $bus;
/**
* The name of the serializer class to output results with.
*
* @var string
*/
public static $serializer = 'Flarum\Api\Serializers\UserSerializer';
/**
* Instantiate the action.
*
* @param \Illuminate\Contracts\Bus\Dispatcher $bus
*/
public function __construct(Dispatcher $bus)
{ {
$userId = array_get($routeParams, 'id'); $this->bus = $bus;
$file = $request->file('avatar'); }
$user = $this->dispatch( /**
new UploadAvatarCommand($userId, $file, $this->actor->getUser()), * Upload an avatar for a user, and return the user ready to be serialized
$routeParams * and assigned to the JsonApi response.
*
* @param \Flarum\Api\JsonApiRequest $request
* @param \Flarum\Api\JsonApiResponse $response
* @return \Flarum\Core\Models\User
*/
protected function data(JsonApiRequest $request, JsonApiResponse $response)
{
return $this->bus->dispatch(
new UploadAvatarCommand($request->get('id'), $request->http->file('avatar'), $request->actor->getUser())
); );
$serializer = new UserSerializer;
$document = $this->document()->setData($serializer->resource($user));
return $this->respondWithDocument($document);
} }
} }

View File

@ -1,17 +0,0 @@
<?php namespace Flarum\Api\Events;
class WillRespondWithDocument
{
public $document;
public $statusCode;
public $headers;
public function __construct($document, &$statusCode, &$headers)
{
$this->document = $document;
$this->statusCode = $statusCode;
$this->headers = $headers;
}
}

View File

@ -9,17 +9,17 @@ class Request
public $actor; public $actor;
public $httpRequest; public $http;
public function __construct(array $input, Actor $actor, IlluminateRequest $httpRequest = null) public function __construct(array $input, Actor $actor, IlluminateRequest $http = null)
{ {
$this->input = $input; $this->input = $input;
$this->actor = $actor; $this->actor = $actor;
$this->httpRequest = $httpRequest; $this->http = $http;
} }
public function get($key, $default = null) public function get($key, $default = null)
{ {
return isset($this->input[$key]) ? $this->input[$key] : $default; return array_get($this->input, $key, $default);
} }
} }

View File

@ -6,13 +6,12 @@ class EditPostCommand
public $user; public $user;
public $content; public $data;
public $isHidden; public function __construct($postId, $user, $data)
public function __construct($postId, $user)
{ {
$this->postId = $postId; $this->postId = $postId;
$this->user = $user; $this->user = $user;
$this->data = $data;
} }
} }

View File

@ -6,21 +6,12 @@ class EditUserCommand
public $user; public $user;
public $username; public $data;
public $email; public function __construct($userId, $user, $data)
public $password;
public $bio;
public $readTime;
public $preferences;
public function __construct($userId, $user)
{ {
$this->userId = $userId; $this->userId = $userId;
$this->user = $user; $this->user = $user;
$this->data = $data;
} }
} }

View File

@ -4,14 +4,14 @@ class PostReplyCommand
{ {
public $discussionId; public $discussionId;
public $content;
public $user; public $user;
public function __construct($discussionId, $content, $user) public $data;
public function __construct($discussionId, $user, $data)
{ {
$this->discussionId = $discussionId; $this->discussionId = $discussionId;
$this->content = $content;
$this->user = $user; $this->user = $user;
$this->data = $data;
} }
} }

View File

@ -6,18 +6,12 @@ class RegisterUserCommand
public $user; public $user;
public $username; public $data;
public $email; public function __construct($user, $forum, $data)
public $password;
public function __construct($username, $email, $password, $user, $forum)
{ {
$this->username = $username;
$this->email = $email;
$this->password = $password;
$this->user = $user; $this->user = $user;
$this->forum = $forum; $this->forum = $forum;
$this->data = $data;
} }
} }

View File

@ -22,15 +22,17 @@ class EditPostCommandHandler
$post->assertCan($user, 'edit'); $post->assertCan($user, 'edit');
if (isset($command->content)) { if (isset($command->data['content'])) {
$post->revise($command->content, $user); $post->revise($command->data['content'], $user);
} }
if ($command->isHidden === true) { if (isset($command->data['isHidden'])) {
if ($command->data['isHidden']) {
$post->hide($user); $post->hide($user);
} elseif ($command->isHidden === false) { } else {
$post->restore($user); $post->restore($user);
} }
}
event(new PostWillBeSaved($post, $command)); event(new PostWillBeSaved($post, $command));

View File

@ -22,23 +22,28 @@ class EditUserCommandHandler
$userToEdit->assertCan($user, 'edit'); $userToEdit->assertCan($user, 'edit');
if (isset($command->username)) { if (isset($command->data['username'])) {
$userToEdit->rename($command->username); $userToEdit->rename($command->data['username']);
} }
if (isset($command->email)) {
$userToEdit->changeEmail($command->email); if (isset($command->data['email'])) {
$userToEdit->changeEmail($command->data['email']);
} }
if (isset($command->password)) {
$userToEdit->changePassword($command->password); if (isset($command->data['password'])) {
$userToEdit->changePassword($command->data['password']);
} }
if (isset($command->bio)) {
$userToEdit->changeBio($command->bio); if (isset($command->data['bio'])) {
$userToEdit->changeBio($command->data['bio']);
} }
if (! empty($command->readTime)) {
if (! empty($command->data['readTime'])) {
$userToEdit->markAllAsRead(); $userToEdit->markAllAsRead();
} }
if (! empty($command->preferences)) {
foreach ($command->preferences as $k => $v) { if (! empty($command->data['preferences'])) {
foreach ($command->data['preferences'] as $k => $v) {
$userToEdit->setPreference($k, $v); $userToEdit->setPreference($k, $v);
} }
} }

View File

@ -34,7 +34,7 @@ class PostReplyCommandHandler
// opportunity to alter the post entity based on data in the command. // opportunity to alter the post entity based on data in the command.
$post = CommentPost::reply( $post = CommentPost::reply(
$command->discussionId, $command->discussionId,
$command->content, array_get($command->data, 'content'),
$user->id $user->id
); );

View File

@ -20,9 +20,9 @@ class RegisterUserCommandHandler
// Before persistance, though, fire an event to give plugins an // Before persistance, though, fire an event to give plugins an
// opportunity to alter the post entity based on data in the command. // opportunity to alter the post entity based on data in the command.
$user = User::register( $user = User::register(
$command->username, array_get($command->data, 'username'),
$command->email, array_get($command->data, 'email'),
$command->password array_get($command->data, 'password')
); );
event(new UserWillBeSaved($user, $command)); event(new UserWillBeSaved($user, $command));

View File

@ -41,7 +41,7 @@ class StartDiscussionCommandHandler
// will trigger a domain event that is slightly semantically incorrect // will trigger a domain event that is slightly semantically incorrect
// in this situation (PostWasPosted), we may need to reconsider someday. // in this situation (PostWasPosted), we may need to reconsider someday.
$post = $this->bus->dispatch( $post = $this->bus->dispatch(
new PostReplyCommand($discussion->id, array_get($command->data, 'content'), $command->user) new PostReplyCommand($discussion->id, $command->user, $command->data)
); );
return $post->discussion; return $post->discussion;

View File

@ -19,6 +19,6 @@ class FulltextGambit extends GambitAbstract
$searcher->query()->whereIn('id', $users); $searcher->query()->whereIn('id', $users);
$searcher->setDefaultSort($users); $searcher->setDefaultSort(['id' => $users]);
} }
} }

View File

@ -8,13 +8,10 @@ class UserSearchCriteria
public $sort; public $sort;
public $order; public function __construct($user, $query, $sort)
public function __construct($user, $query, $sort, $order)
{ {
$this->user = $user; $this->user = $user;
$this->query = $query; $this->query = $query;
$this->sort = $sort; $this->sort = $sort;
$this->order = $order;
} }
} }

View File

@ -4,23 +4,18 @@ use Flarum\Core\Models\User;
use Flarum\Core\Search\SearcherInterface; use Flarum\Core\Search\SearcherInterface;
use Flarum\Core\Search\GambitManager; use Flarum\Core\Search\GambitManager;
use Flarum\Core\Repositories\UserRepositoryInterface; use Flarum\Core\Repositories\UserRepositoryInterface;
use Flarum\Core\Events\UserSearchWillBePerformed;
class UserSearcher implements SearcherInterface class UserSearcher implements SearcherInterface
{ {
public $query; protected $query;
protected $sortMap = [ protected $gambits;
'username' => ['username', 'asc'],
'posts' => ['comments_count', 'desc'],
'discussions' => ['discussions_count', 'desc'],
'lastActive' => ['last_seen_time', 'desc'],
'created' => ['join_time', 'asc']
];
protected $defaultSort = 'username';
protected $users; protected $users;
protected $defaultSort = ['username' => 'asc'];
public function __construct(GambitManager $gambits, UserRepositoryInterface $users) public function __construct(GambitManager $gambits, UserRepositoryInterface $users)
{ {
$this->gambits = $gambits; $this->gambits = $gambits;
@ -37,7 +32,7 @@ class UserSearcher implements SearcherInterface
return $this->query->getQuery(); return $this->query->getQuery();
} }
public function search(UserSearchCriteria $criteria, $count = null, $start = 0, $load = []) public function search(UserSearchCriteria $criteria, $limit = null, $offset = 0, $load = [])
{ {
$this->user = $criteria->user; $this->user = $criteria->user;
$this->query = $this->users->query()->whereCan($criteria->user, 'view'); $this->query = $this->users->query()->whereCan($criteria->user, 'view');
@ -46,24 +41,23 @@ class UserSearcher implements SearcherInterface
$total = $this->query->count(); $total = $this->query->count();
$sort = $criteria->sort; $sort = $criteria->sort ?: $this->defaultSort;
if (empty($sort)) {
$sort = $this->defaultSort; foreach ($sort as $field => $order) {
} if (is_array($order)) {
if (is_array($sort)) { foreach ($order as $value) {
foreach ($sort as $id) { $this->query->orderByRaw(snake_case($field).' != ?', [$value]);
$this->query->orderByRaw('id != '.(int) $id);
} }
} else { } else {
list($column, $order) = $this->sortMap[$sort]; $this->query->orderBy(snake_case($field), $order);
$this->query->orderBy($column, $criteria->order ?: $order); }
} }
if ($start > 0) { if ($offset > 0) {
$this->query->skip($start); $this->query->skip($offset);
} }
if ($count > 0) { if ($limit > 0) {
$this->query->take($count + 1); $this->query->take($limit + 1);
} }
$users = $this->query->get(); $users = $this->query->get();

View File

@ -8,6 +8,7 @@ use Config;
use View; use View;
use DB; use DB;
use Flarum\Forum\Events\RenderView; use Flarum\Forum\Events\RenderView;
use Flarum\Api\Request as ApiRequest;
class IndexAction extends BaseAction class IndexAction extends BaseAction
{ {
@ -24,12 +25,13 @@ class IndexAction extends BaseAction
'token' => Cookie::get('flarum_remember') 'token' => Cookie::get('flarum_remember')
]; ];
$response = $this->callAction('Flarum\Api\Actions\Users\ShowAction', ['id' => $user->id]); $response = app('Flarum\Api\Actions\Users\ShowAction')
$response = $response->getData(); ->handle(new ApiRequest(['id' => $user->id], $this->actor))
->content->toArray();
$data = [$response->data]; $data = [$response['data']];
if (isset($response->included)) { if (isset($response['included'])) {
$data = array_merge($data, $response->included); $data = array_merge($data, $response['included']);
} }
} }