1
0
mirror of https://github.com/flarum/core.git synced 2025-10-18 10:16:09 +02:00

Massive refactor

- Use contextual namespaces within Flarum\Core
- Clean up and docblock everything
- Refactor Activity/Notification blueprint stuff
- Refactor Formatter stuff
- Refactor Search stuff
- Upgrade to JSON-API 1.0
- Removed “addedPosts” and “removedPosts” relationships from discussion
API. This was used for adding/removing event posts after renaming a
discussion etc. Instead we should make an additional request to get all
new posts

Todo:
- Fix Extenders and extensions
- Get rid of repository interfaces
- Fix other bugs I’ve inevitably introduced
This commit is contained in:
Toby Zerner
2015-07-04 12:24:48 +09:30
parent 12dd550a14
commit a74b40fe47
324 changed files with 6443 additions and 4197 deletions

52
src/Api/AccessToken.php Normal file
View File

@@ -0,0 +1,52 @@
<?php namespace Flarum\Api;
use Flarum\Core\Model;
class AccessToken extends Model
{
/**
* {@inheritdoc}
*/
protected $table = 'access_tokens';
/**
* Use a custom primary key for this model.
*
* @var bool
*/
public $incrementing = false;
/**
* {@inheritdoc}
*/
protected $dates = ['created_at', 'expires_at'];
/**
* Generate an access token for the specified user.
*
* @param int $userId
* @param int $minutes
* @return static
*/
public static function generate($userId, $minutes = 60)
{
$token = new static;
$token->id = str_random(40);
$token->user_id = $userId;
$token->created_at = time();
$token->expires_at = time() + $minutes * 60;
return $token;
}
/**
* Define the relationship with the owner of this access token.
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function user()
{
return $this->belongsTo('Flarum\Core\Users\User');
}
}

View File

@@ -7,7 +7,7 @@ interface ActionInterface
/**
* Handle a request to the API, returning an HTTP response.
*
* @param \Flarum\Api\Request $request
* @param Request $request
* @return \Psr\Http\Message\ResponseInterface
*/
public function handle(Request $request);

View File

@@ -1,7 +1,7 @@
<?php namespace Flarum\Api\Actions\Activity;
use Flarum\Core\Repositories\UserRepositoryInterface;
use Flarum\Core\Repositories\ActivityRepositoryInterface;
use Flarum\Core\Users\UserRepositoryInterface;
use Flarum\Core\Activity\ActivityRepositoryInterface;
use Flarum\Api\Actions\SerializeCollectionAction;
use Flarum\Api\JsonApiRequest;
use Tobscure\JsonApi\Document;
@@ -9,12 +9,12 @@ use Tobscure\JsonApi\Document;
class IndexAction extends SerializeCollectionAction
{
/**
* @var \Flarum\Core\Repositories\UserRepositoryInterface
* @var UserRepositoryInterface
*/
protected $users;
/**
* @var \Flarum\Core\Repositories\ActivityRepositoryInterface
* @var ActivityRepositoryInterface
*/
protected $activity;
@@ -58,10 +58,8 @@ class IndexAction extends SerializeCollectionAction
public static $sort;
/**
* Instantiate the action.
*
* @param \Flarum\Core\Repositories\UserRepositoryInterface $users
* @param \Flarum\Core\Repositories\ActivityRepositoryInterface $activity
* @param UserRepositoryInterface $users
* @param ActivityRepositoryInterface $activity
*/
public function __construct(UserRepositoryInterface $users, ActivityRepositoryInterface $activity)
{
@@ -73,17 +71,24 @@ class IndexAction extends SerializeCollectionAction
* Get the activity results, ready to be serialized and assigned to the
* document response.
*
* @param \Flarum\Api\JsonApiRequest $request
* @param \Tobscure\JsonApi\Document $document
* @param JsonApiRequest $request
* @param Document $document
* @return \Illuminate\Database\Eloquent\Collection
*/
protected function data(JsonApiRequest $request, Document $document)
{
$actor = $request->actor->getUser();
$userId = $request->get('filter.user');
$actor = $request->actor;
$user = $this->users->findOrFail($request->get('users'), $actor);
$user = $this->users->findOrFail($userId, $actor);
return $this->activity->findByUser($user->id, $actor, $request->limit, $request->offset, $request->get('type'))
return $this->activity->findByUser(
$user->id,
$actor,
$request->limit,
$request->offset,
$request->get('filter.type')
)
->load($request->include);
}
}

View File

@@ -1,8 +1,7 @@
<?php namespace Flarum\Api\Actions\Discussions;
use Flarum\Core\Commands\StartDiscussionCommand;
use Flarum\Core\Commands\ReadDiscussionCommand;
use Flarum\Core\Models\Forum;
use Flarum\Core\Discussions\Commands\StartDiscussion;
use Flarum\Core\Discussions\Commands\ReadDiscussion;
use Flarum\Api\Actions\CreateAction as BaseCreateAction;
use Flarum\Api\JsonApiRequest;
use Illuminate\Contracts\Bus\Dispatcher;
@@ -12,17 +11,10 @@ class CreateAction extends BaseCreateAction
/**
* The command bus.
*
* @var \Illuminate\Contracts\Bus\Dispatcher
* @var Dispatcher
*/
protected $bus;
/**
* The default forum instance.
*
* @var \Flarum\Core\Models\Forum
*/
protected $forum;
/**
* @inheritdoc
*/
@@ -67,35 +59,33 @@ class CreateAction extends BaseCreateAction
/**
* Instantiate the action.
*
* @param \Illuminate\Contracts\Bus\Dispatcher $bus
* @param \Flarum\Core\Models\Forum $forum
* @param Dispatcher $bus
*/
public function __construct(Dispatcher $bus, Forum $forum)
public function __construct(Dispatcher $bus)
{
$this->bus = $bus;
$this->forum = $forum;
}
/**
* Create a discussion according to input from the API request.
*
* @param JsonApiRequest $request
* @return \Flarum\Core\Models\Model
* @return \Flarum\Core\Discussions\Discussion
*/
protected function create(JsonApiRequest $request)
{
$user = $request->actor->getUser();
$actor = $request->actor;
$discussion = $this->bus->dispatch(
new StartDiscussionCommand($user, $this->forum, $request->get('data'))
new StartDiscussion($actor, $request->get('data'))
);
// After creating the discussion, we assume that the user has seen all
// of the posts in the discussion; thus, we will mark the discussion
// as read if they are logged in.
if ($user->exists) {
if ($actor->exists) {
$this->bus->dispatch(
new ReadDiscussionCommand($discussion->id, $user, 1)
new ReadDiscussion($discussion->id, $actor, 1)
);
}

View File

@@ -1,6 +1,6 @@
<?php namespace Flarum\Api\Actions\Discussions;
use Flarum\Core\Commands\DeleteDiscussionCommand;
use Flarum\Core\Discussions\Commands\DeleteDiscussion;
use Flarum\Api\Actions\DeleteAction as BaseDeleteAction;
use Flarum\Api\Request;
use Illuminate\Contracts\Bus\Dispatcher;
@@ -8,16 +8,12 @@ use Illuminate\Contracts\Bus\Dispatcher;
class DeleteAction extends BaseDeleteAction
{
/**
* The command bus.
*
* @var \Illuminate\Contracts\Bus\Dispatcher
* @var Dispatcher
*/
protected $bus;
/**
* Instantiate the action.
*
* @param \Illuminate\Contracts\Bus\Dispatcher $bus
* @param Dispatcher $bus
*/
public function __construct(Dispatcher $bus)
{
@@ -25,15 +21,16 @@ class DeleteAction extends BaseDeleteAction
}
/**
* Delete a discussion.
*
* @param \Flarum\Api\Request $request
* @return void
* {@inheritdoc}
*/
protected function delete(Request $request)
{
$id = $request->get('id');
$actor = $request->actor;
$input = $request->all();
$this->bus->dispatch(
new DeleteDiscussionCommand($request->get('id'), $request->actor->getUser())
new DeleteDiscussion($id, $actor, $input)
);
}
}

View File

@@ -1,7 +1,7 @@
<?php namespace Flarum\Api\Actions\Discussions;
use Flarum\Core\Search\Discussions\DiscussionSearchCriteria;
use Flarum\Core\Search\Discussions\DiscussionSearcher;
use Flarum\Core\Search\SearchCriteria;
use Flarum\Core\Discussions\Search\DiscussionSearcher;
use Flarum\Api\Actions\SerializeCollectionAction;
use Flarum\Api\JsonApiRequest;
use Flarum\Http\UrlGeneratorInterface;
@@ -10,16 +10,12 @@ use Tobscure\JsonApi\Document;
class IndexAction extends SerializeCollectionAction
{
/**
* The discussion searcher.
*
* @var \Flarum\Core\Search\Discussions\DiscussionSearcher
* @var DiscussionSearcher
*/
protected $searcher;
/**
* The URL generator.
*
* @var \Flarum\Http\UrlGeneratorInterface
* @var UrlGeneratorInterface
*/
protected $url;
@@ -67,10 +63,8 @@ class IndexAction extends SerializeCollectionAction
public static $sort;
/**
* Instantiate the action.
*
* @param \Flarum\Core\Search\Discussions\DiscussionSearcher $searcher
* @param \Flarum\Http\UrlGeneratorInterface $url
* @param DiscussionSearcher $searcher
* @param UrlGeneratorInterface $url
*/
public function __construct(DiscussionSearcher $searcher, UrlGeneratorInterface $url)
{
@@ -82,21 +76,23 @@ class IndexAction extends SerializeCollectionAction
* Get the discussion results, ready to be serialized and assigned to the
* document response.
*
* @param \Flarum\Api\JsonApiRequest $request
* @param \Tobscure\JsonApi\Document $document
* @param JsonApiRequest $request
* @param Document $document
* @return \Illuminate\Database\Eloquent\Collection
*/
protected function data(JsonApiRequest $request, Document $document)
{
$criteria = new DiscussionSearchCriteria(
$request->actor->getUser(),
$request->get('q'),
$criteria = new SearchCriteria(
$request->actor,
$request->get('filter.q'),
$request->sort
);
$load = array_merge($request->include, ['state']);
$results = $this->searcher->search($criteria, $request->limit, $request->offset, $load);
// TODO: add query params (filter, sort, include) to the pagination URLs
static::addPaginationLinks(
$document,
$request,
@@ -104,6 +100,6 @@ class IndexAction extends SerializeCollectionAction
$results->areMoreResults()
);
return $results->getDiscussions();
return $results->getResults();
}
}

View File

@@ -1,7 +1,7 @@
<?php namespace Flarum\Api\Actions\Discussions;
use Flarum\Core\Repositories\DiscussionRepositoryInterface;
use Flarum\Core\Repositories\PostRepositoryInterface;
use Flarum\Core\Discussions\DiscussionRepositoryInterface;
use Flarum\Core\Posts\PostRepositoryInterface;
use Flarum\Api\Actions\SerializeResourceAction;
use Flarum\Api\Actions\Posts\GetsPosts;
use Flarum\Api\JsonApiRequest;
@@ -12,15 +12,10 @@ class ShowAction extends SerializeResourceAction
use GetsPosts;
/**
* @var \Flarum\Core\Repositories\DiscussionRepositoryInterface
* @var \Flarum\Core\Discussions\DiscussionRepositoryInterface
*/
protected $discussions;
/**
* @var \Flarum\Core\Repositories\PostRepositoryInterface
*/
protected $posts;
/**
* @inheritdoc
*/
@@ -69,8 +64,8 @@ class ShowAction extends SerializeResourceAction
/**
* Instantiate the action.
*
* @param \Flarum\Core\Repositories\DiscussionRepositoryInterface $discussions
* @param \Flarum\Core\Repositories\PostRepositoryInterface $posts
* @param DiscussionRepositoryInterface $discussions
* @param PostRepositoryInterface $posts
*/
public function __construct(DiscussionRepositoryInterface $discussions, PostRepositoryInterface $posts)
{
@@ -82,25 +77,29 @@ class ShowAction extends SerializeResourceAction
* Get a single discussion, ready to be serialized and assigned to the
* JsonApi response.
*
* @param \Flarum\Api\JsonApiRequest $request
* @param \Tobscure\JsonApi\Document $document
* @return \Illuminate\Database\Eloquent\Collection
* @param JsonApiRequest $request
* @param Document $document
* @return \Flarum\Core\Discussions\Discussion
*/
protected function data(JsonApiRequest $request, Document $document)
{
$user = $request->actor->getUser();
$discussionId = $request->get('id');
$actor = $request->actor;
$discussion = $this->discussions->findOrFail($request->get('id'), $user);
$discussion = $this->discussions->findOrFail($discussionId, $actor);
$discussion->posts_ids = $discussion->visiblePosts($user)->orderBy('time')->lists('id');
$discussion->posts_ids = $discussion->postsVisibleTo($actor)->orderBy('time')->lists('id');
// TODO: Refactor to be simpler, and get posts straight from the
// discussion's postsVisibleTo relation method.
if (in_array('posts', $request->include)) {
$length = strlen($prefix = 'posts.');
$relations = array_filter(array_map(function ($relationship) use ($prefix, $length) {
return substr($relationship, 0, $length) === $prefix ? substr($relationship, $length) : false;
$prefixLength = strlen($prefix = 'posts.');
$postRelations = array_filter(array_map(function ($relation) use ($prefix, $prefixLength) {
return substr($relation, 0, $prefixLength) === $prefix ? substr($relation, $prefixLength) : false;
}, $request->include));
$discussion->posts = $this->getPosts($request, ['discussion_id' => $discussion->id])->load($relations);
$discussion->posts = $this->getPosts($request, ['discussion_id' => $discussion->id])->load($postRelations);
}
return $discussion;

View File

@@ -1,7 +1,7 @@
<?php namespace Flarum\Api\Actions\Discussions;
use Flarum\Core\Commands\EditDiscussionCommand;
use Flarum\Core\Commands\ReadDiscussionCommand;
use Flarum\Core\Discussions\Commands\EditDiscussion;
use Flarum\Core\Discussions\Commands\ReadDiscussion;
use Flarum\Api\Actions\SerializeResourceAction;
use Flarum\Api\JsonApiRequest;
use Illuminate\Contracts\Bus\Dispatcher;
@@ -10,7 +10,7 @@ use Tobscure\JsonApi\Document;
class UpdateAction extends SerializeResourceAction
{
/**
* @var \Illuminate\Contracts\Bus\Dispatcher
* @var Dispatcher
*/
protected $bus;
@@ -22,11 +22,7 @@ class UpdateAction extends SerializeResourceAction
/**
* @inheritdoc
*/
public static $include = [
'addedPosts' => true,
'addedPosts.user' => true,
'addedPosts.discussion' => true
];
public static $include = [];
/**
* @inheritdoc
@@ -54,9 +50,7 @@ class UpdateAction extends SerializeResourceAction
public static $sort;
/**
* Instantiate the action.
*
* @param \Illuminate\Contracts\Bus\Dispatcher $bus
* @param Dispatcher $bus
*/
public function __construct(Dispatcher $bus)
{
@@ -67,24 +61,25 @@ class UpdateAction extends SerializeResourceAction
* Update a discussion according to input from the API request, and return
* it ready to be serialized and assigned to the JsonApi response.
*
* @param \Flarum\Api\JsonApiRequest $request
* @param \Tobscure\JsonApi\Document $document
* @return \Illuminate\Database\Eloquent\Collection
* @param JsonApiRequest $request
* @param Document $document
* @return \Flarum\Core\Discussions\Discussion
*/
protected function data(JsonApiRequest $request, Document $document)
{
$user = $request->actor->getUser();
$actor = $request->actor;
$discussionId = $request->get('id');
$data = $request->get('data');
if ($data = array_except($request->get('data'), ['readNumber'])) {
$discussion = $this->bus->dispatch(
new EditDiscussionCommand($discussionId, $user, $data)
);
}
$discussion = $this->bus->dispatch(
new EditDiscussion($discussionId, $actor, $data)
);
if ($readNumber = $request->get('data.readNumber')) {
// TODO: Refactor the ReadDiscussion (state) command into EditDiscussion?
// That's what extensions will do anyway.
if ($readNumber = array_get($data, 'attributes.readNumber')) {
$state = $this->bus->dispatch(
new ReadDiscussionCommand($discussionId, $user, $readNumber)
new ReadDiscussion($discussionId, $actor, $readNumber)
);
$discussion = $state->discussion;

View File

@@ -2,7 +2,7 @@
use Flarum\Api\Request;
use Flarum\Core\Repositories\UserRepositoryInterface;
use Flarum\Core\Commands\RequestPasswordResetCommand;
use Flarum\Core\Commands\RequestPasswordReset;
use Illuminate\Contracts\Bus\Dispatcher;
use Zend\Diactoros\Response\EmptyResponse;
@@ -29,7 +29,7 @@ class ForgotAction extends JsonApiAction
$email = $request->get('email');
$this->bus->dispatch(
new RequestPasswordResetCommand($email)
new RequestPasswordReset($email)
);
return new EmptyResponse();

View File

@@ -45,9 +45,9 @@ class ShowAction extends SerializeResourceAction
* Get the forum, ready to be serialized and assigned to the JsonApi
* response.
*
* @param \Flarum\Api\JsonApiRequest $request
* @param \Tobscure\JsonApi\Document $document
* @return array
* @param JsonApiRequest $request
* @param Document $document
* @return \Flarum\Core\Forum
*/
protected function data(JsonApiRequest $request, Document $document)
{

View File

@@ -1,6 +1,6 @@
<?php namespace Flarum\Api\Actions\Groups;
use Flarum\Core\Models\Group;
use Flarum\Core\Users\Group;
use Flarum\Api\Actions\SerializeCollectionAction;
use Flarum\Api\JsonApiRequest;
use Tobscure\JsonApi\Document;
@@ -46,12 +46,12 @@ class IndexAction extends SerializeCollectionAction
* Get the groups, ready to be serialized and assigned to the document
* response.
*
* @param \Flarum\Api\JsonApiRequest $request
* @param \Tobscure\JsonApi\Document $document
* @param JsonApiRequest $request
* @param Document $document
* @return \Illuminate\Database\Eloquent\Collection
*/
protected function data(JsonApiRequest $request, Document $document)
{
return Group::get();
return Group::all();
}
}

View File

@@ -12,11 +12,12 @@ abstract class JsonApiAction implements ActionInterface
* Handle an API request and return an API response, handling any relevant
* (API-related) exceptions that are thrown.
*
* @param \Flarum\Api\Request $request
* @param Request $request
* @return \Psr\Http\Message\ResponseInterface
*/
public function handle(Request $request)
{
// TODO: Move this error handling code to middleware?
try {
return $this->respond($request);
} catch (ValidationFailureException $e) {
@@ -38,7 +39,7 @@ abstract class JsonApiAction implements ActionInterface
/**
* Handle an API request and return an API response.
*
* @param \Flarum\Api\Request $request
* @param Request $request
* @return \Psr\Http\Message\ResponseInterface
*/
abstract protected function respond(Request $request);

View File

@@ -1,6 +1,6 @@
<?php namespace Flarum\Api\Actions\Notifications;
use Flarum\Core\Repositories\NotificationRepositoryInterface;
use Flarum\Core\Notifications\NotificationRepositoryInterface;
use Flarum\Core\Exceptions\PermissionDeniedException;
use Flarum\Api\Actions\SerializeCollectionAction;
use Flarum\Api\JsonApiRequest;
@@ -9,7 +9,7 @@ use Tobscure\JsonApi\Document;
class IndexAction extends SerializeCollectionAction
{
/**
* @var \Flarum\Core\Repositories\NotificationRepositoryInterface
* @var NotificationRepositoryInterface
*/
protected $notifications;
@@ -55,7 +55,7 @@ class IndexAction extends SerializeCollectionAction
/**
* Instantiate the action.
*
* @param \Flarum\Core\Repositories\NotificationRepositoryInterface $notifications
* @param NotificationRepositoryInterface $notifications
*/
public function __construct(NotificationRepositoryInterface $notifications)
{
@@ -66,22 +66,22 @@ class IndexAction extends SerializeCollectionAction
* Get the notification results, ready to be serialized and assigned to the
* document response.
*
* @param \Flarum\Api\JsonApiRequest $request
* @param \Tobscure\JsonApi\Document $document
* @param JsonApiRequest $request
* @param Document $document
* @return \Illuminate\Database\Eloquent\Collection
* @throws PermissionDeniedException
*/
protected function data(JsonApiRequest $request, Document $document)
{
if (! $request->actor->isAuthenticated()) {
$actor = $request->actor;
if ($actor->isGuest()) {
throw new PermissionDeniedException;
}
$user = $request->actor->getUser();
$actor->markNotificationsAsRead()->save();
$user->markNotificationsAsRead()->save();
return $this->notifications->findByUser($user, $request->limit, $request->offset)
return $this->notifications->findByUser($actor, $request->limit, $request->offset)
->load($request->include);
}
}

View File

@@ -1,6 +1,6 @@
<?php namespace Flarum\Api\Actions\Notifications;
use Flarum\Core\Commands\ReadNotificationCommand;
use Flarum\Core\Notifications\Commands\ReadNotification;
use Flarum\Api\Actions\SerializeResourceAction;
use Flarum\Api\JsonApiRequest;
use Illuminate\Contracts\Bus\Dispatcher;
@@ -9,7 +9,7 @@ use Tobscure\JsonApi\Document;
class UpdateAction extends SerializeResourceAction
{
/**
* @var \Illuminate\Contracts\Bus\Dispatcher
* @var Dispatcher
*/
protected $bus;
@@ -49,9 +49,7 @@ class UpdateAction extends SerializeResourceAction
public static $sort;
/**
* Instantiate the action.
*
* @param \Illuminate\Contracts\Bus\Dispatcher $bus
* @param Dispatcher $bus
*/
public function __construct(Dispatcher $bus)
{
@@ -62,14 +60,14 @@ class UpdateAction extends SerializeResourceAction
* Mark a notification as read, and return it ready to be serialized and
* assigned to the JsonApi response.
*
* @param \Flarum\Api\JsonApiRequest $request
* @param \Tobscure\JsonApi\Document $document
* @return \Illuminate\Database\Eloquent\Collection
* @param JsonApiRequest $request
* @param Document $document
* @return \Flarum\Core\Notifications\Notification
*/
protected function data(JsonApiRequest $request, Document $document)
{
return $this->bus->dispatch(
new ReadNotificationCommand($request->get('id'), $request->actor->getUser())
new ReadNotification($request->get('id'), $request->actor)
);
}
}

View File

@@ -1,7 +1,7 @@
<?php namespace Flarum\Api\Actions\Posts;
use Flarum\Core\Commands\PostReplyCommand;
use Flarum\Core\Commands\ReadDiscussionCommand;
use Flarum\Core\Posts\Commands\PostReply;
use Flarum\Core\Discussions\Commands\ReadDiscussion;
use Flarum\Api\Actions\CreateAction as BaseCreateAction;
use Flarum\Api\JsonApiRequest;
use Illuminate\Contracts\Bus\Dispatcher;
@@ -9,7 +9,7 @@ use Illuminate\Contracts\Bus\Dispatcher;
class CreateAction extends BaseCreateAction
{
/**
* @var \Illuminate\Contracts\Bus\Dispatcher
* @var Dispatcher
*/
protected $bus;
@@ -53,7 +53,7 @@ class CreateAction extends BaseCreateAction
/**
* Instantiate the action.
*
* @param \Illuminate\Contracts\Bus\Dispatcher $bus
* @param Dispatcher $bus
*/
public function __construct(Dispatcher $bus)
{
@@ -64,24 +64,23 @@ class CreateAction extends BaseCreateAction
* Reply to a discussion according to input from the API request.
*
* @param JsonApiRequest $request
* @return \Flarum\Core\Models\Model
* @return \Flarum\Core\Posts\Post
*/
protected function create(JsonApiRequest $request)
{
$user = $request->actor->getUser();
$discussionId = $request->get('data.links.discussion.linkage.id');
$actor = $request->actor;
$discussionId = $request->get('data.relationships.discussion.data.id');
$post = $this->bus->dispatch(
new PostReplyCommand($discussionId, $user, $request->get('data'))
new PostReply($discussionId, $actor, $request->get('data'))
);
// 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
// they are logged in.
if ($user->exists) {
if ($actor->exists) {
$this->bus->dispatch(
new ReadDiscussionCommand($discussionId, $user, $post->number)
new ReadDiscussion($discussionId, $actor, $post->number)
);
}

View File

@@ -1,6 +1,6 @@
<?php namespace Flarum\Api\Actions\Posts;
use Flarum\Core\Commands\DeletePostCommand;
use Flarum\Core\Posts\Commands\DeletePost;
use Flarum\Api\Actions\DeleteAction as BaseDeleteAction;
use Flarum\Api\Request;
use Illuminate\Contracts\Bus\Dispatcher;
@@ -8,14 +8,12 @@ use Illuminate\Contracts\Bus\Dispatcher;
class DeleteAction extends BaseDeleteAction
{
/**
* @var \Illuminate\Contracts\Bus\Dispatcher
* @var Dispatcher
*/
protected $bus;
/**
* Instantiate the action.
*
* @param \Illuminate\Contracts\Bus\Dispatcher $bus
* @param Dispatcher $bus
*/
public function __construct(Dispatcher $bus)
{
@@ -25,13 +23,13 @@ class DeleteAction extends BaseDeleteAction
/**
* Delete a post.
*
* @param \Flarum\Api\Request $request
* @param Request $request
* @return void
*/
protected function delete(Request $request)
{
$this->bus->dispatch(
new DeletePostCommand($request->get('id'), $request->actor->getUser())
new DeletePost($request->get('id'), $request->actor)
);
}
}

View File

@@ -4,12 +4,22 @@ use Flarum\Api\JsonApiRequest;
trait GetsPosts
{
/**
* @var \Flarum\Core\Posts\PostRepositoryInterface
*/
protected $posts;
/**
* @param JsonApiRequest $request
* @param array $where
* @return \Illuminate\Database\Eloquent\Collection
*/
protected function getPosts(JsonApiRequest $request, array $where)
{
$user = $request->actor->getUser();
$actor = $request->actor;
if (isset($where['discussion_id']) && ($near = $request->get('near')) > 1) {
$offset = $this->posts->getIndexForNumber($where['discussion_id'], $near, $user);
if (isset($where['discussion_id']) && ($near = $request->get('page.near')) > 1) {
$offset = $this->posts->getIndexForNumber($where['discussion_id'], $near, $actor);
$offset = max(0, $offset - $request->limit / 2);
} else {
$offset = 0;
@@ -17,7 +27,7 @@ trait GetsPosts
return $this->posts->findWhere(
$where,
$user,
$actor,
$request->sort,
$request->limit,
$offset

View File

@@ -1,6 +1,6 @@
<?php namespace Flarum\Api\Actions\Posts;
use Flarum\Core\Repositories\PostRepositoryInterface;
use Flarum\Core\Posts\PostRepositoryInterface;
use Flarum\Api\Actions\SerializeCollectionAction;
use Flarum\Api\JsonApiRequest;
use Tobscure\JsonApi\Document;
@@ -9,11 +9,6 @@ class IndexAction extends SerializeCollectionAction
{
use GetsPosts;
/**
* @var \Flarum\Core\Repositories\PostRepositoryInterface
*/
protected $posts;
/**
* @inheritdoc
*/
@@ -56,9 +51,7 @@ class IndexAction extends SerializeCollectionAction
public static $sort;
/**
* Instantiate the action.
*
* @param \Flarum\Core\Repositories\PostRepositoryInterface $posts
* @param PostRepositoryInterface $posts
*/
public function __construct(PostRepositoryInterface $posts)
{
@@ -69,26 +62,26 @@ class IndexAction extends SerializeCollectionAction
* Get the post results, ready to be serialized and assigned to the
* document response.
*
* @param \Flarum\Api\JsonApiRequest $request
* @param \Tobscure\JsonApi\Document $document
* @param JsonApiRequest $request
* @param Document $document
* @return \Illuminate\Database\Eloquent\Collection
*/
protected function data(JsonApiRequest $request, Document $document)
{
$postIds = (array) $request->get('ids');
$user = $request->actor->getUser();
$actor = $request->actor;
if (count($postIds)) {
$posts = $this->posts->findByIds($postIds, $user);
$posts = $this->posts->findByIds($postIds, $actor);
} else {
$where = [];
if ($discussionId = $request->get('discussions')) {
if ($discussionId = $request->get('filter.discussion')) {
$where['discussion_id'] = $discussionId;
}
if ($number = $request->get('number')) {
if ($number = $request->get('page.number')) {
$where['number'] = $number;
}
if ($userId = $request->get('users')) {
if ($userId = $request->get('filter.user')) {
$where['user_id'] = $userId;
}
$posts = $this->getPosts($request, $where);

View File

@@ -1,7 +1,7 @@
<?php namespace Flarum\Api\Actions\Posts;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Flarum\Core\Repositories\PostRepositoryInterface;
use Flarum\Core\Posts\PostRepositoryInterface;
use Flarum\Api\Actions\SerializeResourceAction;
use Flarum\Api\JsonApiRequest;
use Tobscure\JsonApi\Document;
@@ -9,7 +9,7 @@ use Tobscure\JsonApi\Document;
class ShowAction extends SerializeResourceAction
{
/**
* @var \Flarum\Core\Repositories\PostRepositoryInterface
* @var PostRepositoryInterface
*/
protected $posts;
@@ -55,9 +55,7 @@ class ShowAction extends SerializeResourceAction
public static $sort;
/**
* Instantiate the action.
*
* @param \Flarum\Core\Repositories\PostRepositoryInterface $posts
* @param PostRepositoryInterface $posts
*/
public function __construct(PostRepositoryInterface $posts)
{
@@ -68,12 +66,12 @@ class ShowAction extends SerializeResourceAction
* Get a single post, ready to be serialized and assigned to the JsonApi
* response.
*
* @param \Flarum\Api\JsonApiRequest $request
* @param \Tobscure\JsonApi\Document $document
* @return \Illuminate\Database\Eloquent\Collection
* @param JsonApiRequest $request
* @param Document $document
* @return \Flarum\Core\Posts\Post
*/
protected function data(JsonApiRequest $request, Document $document)
{
return $this->posts->findOrFail($request->get('id'), $request->actor->getUser());
return $this->posts->findOrFail($request->get('id'), $request->actor);
}
}

View File

@@ -1,6 +1,6 @@
<?php namespace Flarum\Api\Actions\Posts;
use Flarum\Core\Commands\EditPostCommand;
use Flarum\Core\Posts\Commands\EditPost;
use Flarum\Api\Actions\SerializeResourceAction;
use Flarum\Api\JsonApiRequest;
use Illuminate\Contracts\Bus\Dispatcher;
@@ -9,7 +9,7 @@ use Tobscure\JsonApi\Document;
class UpdateAction extends SerializeResourceAction
{
/**
* @var \Illuminate\Contracts\Bus\Dispatcher
* @var Dispatcher
*/
protected $bus;
@@ -49,9 +49,7 @@ class UpdateAction extends SerializeResourceAction
public static $sort;
/**
* Instantiate the action.
*
* @param \Illuminate\Contracts\Bus\Dispatcher $bus
* @param Dispatcher $bus
*/
public function __construct(Dispatcher $bus)
{
@@ -62,14 +60,14 @@ class UpdateAction extends SerializeResourceAction
* Update a post according to input from the API request, and return it
* ready to be serialized and assigned to the JsonApi response.
*
* @param \Flarum\Api\JsonApiRequest $request
* @param \Tobscure\JsonApi\Document $document
* @param JsonApiRequest $request
* @param Document $document
* @return \Illuminate\Database\Eloquent\Collection
*/
protected function data(JsonApiRequest $request, Document $document)
{
return $this->bus->dispatch(
new EditPostCommand($request->get('id'), $request->actor->getUser(), $request->get('data'))
new EditPost($request->get('id'), $request->actor, $request->get('data'))
);
}
}

View File

@@ -63,8 +63,8 @@ abstract class SerializeAction extends JsonApiAction
/**
* Handle an API request and return an API response.
*
* @param \Flarum\Api\Request $request
* @return \Psr\Http\Message\ResponseInterface
* @param Request $request
* @return JsonResponse
*/
public function respond(Request $request)
{
@@ -78,14 +78,15 @@ abstract class SerializeAction extends JsonApiAction
$serializer = new static::$serializer($request->actor, $request->include, $request->link);
$document->setData($this->serialize($serializer, $data));
return new JsonResponse($document, 200, ['content-type' => 'application/vnd.api+json']);
}
/**
* Get the data to be serialized and assigned to the response document.
*
* @param \Flarum\Api\JsonApiRequest $request
* @param \Tobscure\JsonApi\Document $document
* @param JsonApiRequest $request
* @param Document $document
* @return array
*/
abstract protected function data(JsonApiRequest $request, Document $document);
@@ -93,7 +94,7 @@ abstract class SerializeAction extends JsonApiAction
/**
* Serialize the data as appropriate.
*
* @param \Tobscure\JsonApi\SerializerInterface $serializer
* @param SerializerInterface $serializer
* @param array $data
* @return \Tobscure\JsonApi\Elements\ElementInterface
*/
@@ -103,8 +104,8 @@ abstract class SerializeAction extends JsonApiAction
* Extract parameters from the request input and assign them to the
* request, restricted by the action's specifications.
*
* @param \Flarum\Api\Request $request
* @return void
* @param Request $request
* @return JsonApiRequest
*/
protected static function buildJsonApiRequest(Request $request)
{
@@ -160,8 +161,8 @@ abstract class SerializeAction extends JsonApiAction
* Add pagination links to a JSON-API response, based on input parameters
* and the default parameters of this action.
*
* @param \Tobscure\JsonApi\Document $document
* @param \Flarum\Api\JsonApiRequest $request
* @param Document $document
* @param JsonApiRequest $request
* @param string $url The base URL to build pagination links with.
* @param integer|boolean $total The total number of results (used to build
* a 'last' link), or just true if there are more results but how many

View File

@@ -7,7 +7,7 @@ abstract class SerializeCollectionAction extends SerializeAction
/**
* Serialize the data as appropriate.
*
* @param \Tobscure\JsonApi\SerializerInterface $serializer
* @param SerializerInterface $serializer
* @param array $data
* @return \Tobscure\JsonApi\Elements\Collection
*/

View File

@@ -7,7 +7,7 @@ abstract class SerializeResourceAction extends SerializeAction
/**
* Serialize the data as appropriate.
*
* @param \Tobscure\JsonApi\SerializerInterface $serializer
* @param SerializerInterface $serializer
* @param array $data
* @return \Tobscure\JsonApi\Elements\Resource
*/

View File

@@ -1,10 +1,10 @@
<?php namespace Flarum\Api\Actions;
use Flarum\Api\Commands\GenerateAccessToken;
use Flarum\Api\Request;
use Flarum\Core\Commands\GenerateAccessTokenCommand;
use Flarum\Core\Repositories\UserRepositoryInterface;
use Flarum\Core\Users\UserRepositoryInterface;
use Flarum\Core\Exceptions\PermissionDeniedException;
use Flarum\Core\Events\UserEmailChangeWasRequested;
use Flarum\Core\Users\Events\UserEmailChangeWasRequested;
use Illuminate\Contracts\Bus\Dispatcher;
use Zend\Diactoros\Response\JsonResponse;
@@ -23,7 +23,7 @@ class TokenAction extends JsonApiAction
/**
* Log in and return a token.
*
* @param \Flarum\Api\Request $request
* @param Request $request
* @return \Psr\Http\Message\ResponseInterface
* @throws PermissionDeniedException
*/
@@ -40,6 +40,7 @@ class TokenAction extends JsonApiAction
if (! $user->is_activated) {
event(new UserEmailChangeWasRequested($user, $user->email));
return new JsonResponse([
'code' => 'confirm_email',
'email' => $user->email
@@ -47,7 +48,7 @@ class TokenAction extends JsonApiAction
}
$token = $this->bus->dispatch(
new GenerateAccessTokenCommand($user->id)
new GenerateAccessToken($user->id)
);
return new JsonResponse([

View File

@@ -1,7 +1,6 @@
<?php namespace Flarum\Api\Actions\Users;
use Flarum\Core\Models\Forum;
use Flarum\Core\Commands\RegisterUserCommand;
use Flarum\Core\Users\Commands\RegisterUser;
use Flarum\Api\Actions\CreateAction as BaseCreateAction;
use Flarum\Api\JsonApiRequest;
use Illuminate\Contracts\Bus\Dispatcher;
@@ -9,19 +8,10 @@ use Illuminate\Contracts\Bus\Dispatcher;
class CreateAction extends BaseCreateAction
{
/**
* The command bus.
*
* @var \Illuminate\Contracts\Bus\Dispatcher
* @var Dispatcher
*/
protected $bus;
/**
* The default forum instance.
*
* @var \Flarum\Core\Models\Forum
*/
protected $forum;
/**
* @inheritdoc
*/
@@ -58,27 +48,23 @@ class CreateAction extends BaseCreateAction
public static $sort;
/**
* Instantiate the action.
*
* @param \Illuminate\Contracts\Bus\Dispatcher $bus
* @param \Flarum\Core\Models\Forum $forum
* @param Dispatcher $bus
*/
public function __construct(Dispatcher $bus, Forum $forum)
public function __construct(Dispatcher $bus)
{
$this->bus = $bus;
$this->forum = $forum;
}
/**
* Register a user according to input from the API request.
*
* @param JsonApiRequest $request
* @return \Flarum\Core\Models\Model
* @return \Flarum\Core\Users\User
*/
protected function create(JsonApiRequest $request)
{
return $this->bus->dispatch(
new RegisterUserCommand($request->actor->getUser(), $this->forum, $request->get('data'))
new RegisterUser($request->actor, $request->get('data'))
);
}
}

View File

@@ -1,6 +1,6 @@
<?php namespace Flarum\Api\Actions\Users;
use Flarum\Core\Commands\DeleteUserCommand;
use Flarum\Core\Users\Commands\DeleteUser;
use Flarum\Api\Actions\DeleteAction as BaseDeleteAction;
use Flarum\Api\Request;
use Illuminate\Contracts\Bus\Dispatcher;
@@ -8,16 +8,12 @@ use Illuminate\Contracts\Bus\Dispatcher;
class DeleteAction extends BaseDeleteAction
{
/**
* The command bus.
*
* @var \Illuminate\Contracts\Bus\Dispatcher
* @var Dispatcher
*/
protected $bus;
/**
* Instantiate the action.
*
* @param \Illuminate\Contracts\Bus\Dispatcher $bus
* @param Dispatcher $bus
*/
public function __construct(Dispatcher $bus)
{
@@ -27,13 +23,12 @@ class DeleteAction extends BaseDeleteAction
/**
* Delete a user.
*
* @param \Flarum\Api\Request $request
* @return void
* @param Request $request
*/
protected function delete(Request $request)
{
$this->bus->dispatch(
new DeleteUserCommand($request->get('id'), $request->actor->getUser())
new DeleteUser($request->get('id'), $request->actor)
);
}
}

View File

@@ -1,6 +1,6 @@
<?php namespace Flarum\Api\Actions\Users;
use Flarum\Core\Commands\DeleteAvatarCommand;
use Flarum\Core\Users\Commands\DeleteAvatar;
use Flarum\Api\Actions\SerializeResourceAction;
use Flarum\Api\JsonApiRequest;
use Illuminate\Contracts\Bus\Dispatcher;
@@ -9,7 +9,7 @@ use Tobscure\JsonApi\Document;
class DeleteAvatarAction extends SerializeResourceAction
{
/**
* @var \Illuminate\Contracts\Bus\Dispatcher
* @var Dispatcher
*/
protected $bus;
@@ -19,9 +19,7 @@ class DeleteAvatarAction extends SerializeResourceAction
public static $serializer = 'Flarum\Api\Serializers\UserSerializer';
/**
* Instantiate the action.
*
* @param \Illuminate\Contracts\Bus\Dispatcher $bus
* @param Dispatcher $bus
*/
public function __construct(Dispatcher $bus)
{
@@ -32,14 +30,14 @@ class DeleteAvatarAction extends SerializeResourceAction
* Delete a user's avatar, and return the user ready to be serialized and
* assigned to the JsonApi response.
*
* @param \Flarum\Api\JsonApiRequest $request
* @param \Tobscure\JsonApi\Document $document
* @return \Flarum\Core\Models\Discussion
* @param JsonApiRequest $request
* @param Document $document
* @return \Flarum\Core\Users\User
*/
protected function data(JsonApiRequest $request, Document $document)
{
return $this->bus->dispatch(
new DeleteAvatarCommand($request->get('id'), $request->actor->getUser())
new DeleteAvatar($request->get('id'), $request->actor)
);
}
}

View File

@@ -1,7 +1,7 @@
<?php namespace Flarum\Api\Actions\Users;
use Flarum\Core\Search\Users\UserSearchCriteria;
use Flarum\Core\Search\Users\UserSearcher;
use Flarum\Core\Search\SearchCriteria;
use Flarum\Core\Users\Search\UserSearcher;
use Flarum\Api\Actions\SerializeCollectionAction;
use Flarum\Api\JsonApiRequest;
use Flarum\Http\UrlGeneratorInterface;
@@ -10,16 +10,12 @@ use Tobscure\JsonApi\Document;
class IndexAction extends SerializeCollectionAction
{
/**
* The user searcher.
*
* @var \Flarum\Core\Search\Users\UserSearcher
* @var UserSearcher
*/
protected $searcher;
/**
* The URL generator.
*
* @var \Flarum\Http\UrlGeneratorInterface
* @var UrlGeneratorInterface
*/
protected $url;
@@ -61,10 +57,8 @@ class IndexAction extends SerializeCollectionAction
public static $sort;
/**
* Instantiate the action.
*
* @param \Flarum\Core\Search\Users\UserSearcher $searcher
* @param \Flarum\Http\UrlGeneratorInterface $url
* @param UserSearcher $searcher
* @param UrlGeneratorInterface $url
*/
public function __construct(UserSearcher $searcher, UrlGeneratorInterface $url)
{
@@ -76,15 +70,15 @@ class IndexAction extends SerializeCollectionAction
* Get the user results, ready to be serialized and assigned to the
* document response.
*
* @param \Flarum\Api\JsonApiRequest $request
* @param \Tobscure\JsonApi\Document $document
* @param JsonApiRequest $request
* @param Document $document
* @return \Illuminate\Database\Eloquent\Collection
*/
protected function data(JsonApiRequest $request, Document $document)
{
$criteria = new UserSearchCriteria(
$request->actor->getUser(),
$request->get('q'),
$criteria = new SearchCriteria(
$request->actor,
$request->get('filter.q'),
$request->sort
);
@@ -97,6 +91,6 @@ class IndexAction extends SerializeCollectionAction
$results->areMoreResults()
);
return $results->getUsers();
return $results->getResults();
}
}

View File

@@ -1,6 +1,6 @@
<?php namespace Flarum\Api\Actions\Users;
use Flarum\Core\Repositories\UserRepositoryInterface;
use Flarum\Core\Users\UserRepositoryInterface;
use Flarum\Api\Actions\SerializeResourceAction;
use Flarum\Api\JsonApiRequest;
use Tobscure\JsonApi\Document;
@@ -8,7 +8,7 @@ use Tobscure\JsonApi\Document;
class ShowAction extends SerializeResourceAction
{
/**
* @var \Flarum\Core\Repositories\UserRepositoryInterface
* @var UserRepositoryInterface
*/
protected $users;
@@ -50,9 +50,7 @@ class ShowAction extends SerializeResourceAction
public static $sort;
/**
* Instantiate the action.
*
* @param \Flarum\Core\Repositories\UserRepositoryInterface $users
* @param UserRepositoryInterface $users
*/
public function __construct(UserRepositoryInterface $users)
{
@@ -63,9 +61,9 @@ class ShowAction extends SerializeResourceAction
* Get a single user, ready to be serialized and assigned to the JsonApi
* response.
*
* @param \Flarum\Api\JsonApiRequest $request
* @param \Tobscure\JsonApi\Document $document
* @return \Flarum\Core\Models\Discussion
* @param JsonApiRequest $request
* @param Document $document
* @return \Flarum\Core\Users\User
*/
protected function data(JsonApiRequest $request, Document $document)
{
@@ -75,6 +73,6 @@ class ShowAction extends SerializeResourceAction
$id = $this->users->getIdForUsername($id);
}
return $this->users->findOrFail($id, $request->actor->getUser());
return $this->users->findOrFail($id, $request->actor);
}
}

View File

@@ -1,6 +1,6 @@
<?php namespace Flarum\Api\Actions\Users;
use Flarum\Core\Commands\EditUserCommand;
use Flarum\Core\Users\Commands\EditUser;
use Flarum\Api\Actions\SerializeResourceAction;
use Flarum\Api\JsonApiRequest;
use Illuminate\Contracts\Bus\Dispatcher;
@@ -9,14 +9,14 @@ use Tobscure\JsonApi\Document;
class UpdateAction extends SerializeResourceAction
{
/**
* @var \Illuminate\Contracts\Bus\Dispatcher
* @var Dispatcher
*/
protected $bus;
/**
* @inheritdoc
*/
public static $serializer = 'Flarum\Api\Serializers\UserSerializer';
public static $serializer = 'Flarum\Api\Serializers\CurrentUserSerializer';
/**
* @inheritdoc
@@ -49,9 +49,7 @@ class UpdateAction extends SerializeResourceAction
public static $sort;
/**
* Instantiate the action.
*
* @param \Illuminate\Contracts\Bus\Dispatcher $bus
* @param Dispatcher $bus
*/
public function __construct(Dispatcher $bus)
{
@@ -62,14 +60,14 @@ class UpdateAction extends SerializeResourceAction
* Update a user according to input from the API request, and return it
* ready to be serialized and assigned to the JsonApi response.
*
* @param \Flarum\Api\JsonApiRequest $request
* @param \Tobscure\JsonApi\Document $document
* @return \Flarum\Core\Models\Discussion
* @param JsonApiRequest $request
* @param Document $document
* @return \Flarum\Core\Users\User
*/
protected function data(JsonApiRequest $request, Document $document)
{
return $this->bus->dispatch(
new EditUserCommand($request->get('id'), $request->actor->getUser(), $request->get('data'))
new EditUser($request->get('id'), $request->actor, $request->get('data'))
);
}
}

View File

@@ -1,6 +1,6 @@
<?php namespace Flarum\Api\Actions\Users;
use Flarum\Core\Commands\UploadAvatarCommand;
use Flarum\Core\Users\Commands\UploadAvatar;
use Flarum\Api\Actions\SerializeResourceAction;
use Flarum\Api\JsonApiRequest;
use Illuminate\Contracts\Bus\Dispatcher;
@@ -9,7 +9,7 @@ use Tobscure\JsonApi\Document;
class UploadAvatarAction extends SerializeResourceAction
{
/**
* @var \Illuminate\Contracts\Bus\Dispatcher
* @var Dispatcher
*/
protected $bus;
@@ -49,9 +49,7 @@ class UploadAvatarAction extends SerializeResourceAction
public static $sort;
/**
* Instantiate the action.
*
* @param \Illuminate\Contracts\Bus\Dispatcher $bus
* @param Dispatcher $bus
*/
public function __construct(Dispatcher $bus)
{
@@ -62,17 +60,17 @@ class UploadAvatarAction extends SerializeResourceAction
* Upload an avatar for a user, and return the user ready to be serialized
* and assigned to the JsonApi response.
*
* @param \Flarum\Api\JsonApiRequest $request
* @param \Tobscure\JsonApi\Document $document
* @return \Flarum\Core\Models\Discussion
* @param JsonApiRequest $request
* @param Document $document
* @return \Flarum\Core\Users\User
*/
protected function data(JsonApiRequest $request, Document $document)
{
return $this->bus->dispatch(
new UploadAvatarCommand(
new UploadAvatar(
$request->get('id'),
$request->http->getUploadedFiles()['avatar'],
$request->actor->getUser()
$request->actor
)
);
}

View File

@@ -1,5 +1,6 @@
<?php namespace Flarum\Api;
use Flarum\Core\Users\Guest;
use Flarum\Http\RouteCollection;
use Flarum\Http\UrlGenerator;
use Illuminate\Support\ServiceProvider;
@@ -14,7 +15,9 @@ class ApiServiceProvider extends ServiceProvider
*/
public function register()
{
$this->app->singleton('Flarum\Support\Actor');
$this->app->bind('flarum.actor', function () {
return new Guest;
});
$this->app->singleton(
'Flarum\Http\UrlGeneratorInterface',
@@ -33,11 +36,6 @@ class ApiServiceProvider extends ServiceProvider
*/
public function boot()
{
$this->app->singleton(
'Illuminate\Contracts\Debug\ExceptionHandler',
'Flarum\Api\ExceptionHandler'
);
$this->routes();
}
@@ -94,7 +92,7 @@ class ApiServiceProvider extends ServiceProvider
);
// Edit a user
$routes->put(
$routes->patch(
'/users/{id}',
'flarum.api.users.update',
$this->action('Flarum\Api\Actions\Users\UpdateAction')
@@ -142,7 +140,7 @@ class ApiServiceProvider extends ServiceProvider
);
// Mark a single notification as read
$routes->put(
$routes->patch(
'/notifications/{id}',
'flarum.api.notifications.update',
$this->action('Flarum\Api\Actions\Notifications\UpdateAction')
@@ -175,7 +173,7 @@ class ApiServiceProvider extends ServiceProvider
);
// Edit a discussion
$routes->put(
$routes->patch(
'/discussions/{id}',
'flarum.api.discussions.update',
$this->action('Flarum\Api\Actions\Discussions\UpdateAction')
@@ -202,7 +200,6 @@ class ApiServiceProvider extends ServiceProvider
);
// Create a post
// @todo consider 'discussions/{id}/links/posts'?
$routes->post(
'/posts',
'flarum.api.posts.create',
@@ -217,7 +214,7 @@ class ApiServiceProvider extends ServiceProvider
);
// Edit a post
$routes->put(
$routes->patch(
'/posts/{id}',
'flarum.api.posts.update',
$this->action('Flarum\Api\Actions\Posts\UpdateAction')
@@ -258,7 +255,7 @@ class ApiServiceProvider extends ServiceProvider
);
// Edit a group
$routes->put(
$routes->patch(
'/groups/{id}',
'flarum.api.groups.update',
$this->action('Flarum\Api\Actions\Groups\UpdateAction')
@@ -276,7 +273,7 @@ class ApiServiceProvider extends ServiceProvider
{
return function (ServerRequestInterface $httpRequest, $routeParams) use ($class) {
$action = app($class);
$actor = app('Flarum\Support\Actor');
$actor = app('flarum.actor');
$input = array_merge($httpRequest->getQueryParams(), $httpRequest->getAttributes(), $routeParams);
$request = new Request($input, $actor, $httpRequest);

View File

@@ -1,35 +1,37 @@
<?php
<?php namespace Flarum\Api;
namespace Flarum\Api;
use Flarum\Support\Actor;
use Flarum\Core\Users\User;
use Illuminate\Contracts\Container\Container;
class Client
{
/**
* @var Container
*/
protected $container;
protected $actor;
public function __construct(Container $container, Actor $actor)
/**
* @param Container $container
*/
public function __construct(Container $container)
{
$this->container = $container;
$this->actor = $actor;
}
/**
* Execute the given API action class, pass the input and return its response.
*
* @param User $actor
* @param string $actionClass
* @param array $input
* @return object
*/
public function send($actionClass, array $input = [])
public function send(User $actor, $actionClass, array $input = [])
{
/** @var \Flarum\Api\Actions\JsonApiAction $action */
$action = $this->container->make($actionClass);
$response = $action->handle(new Request($input, $this->actor));
$response = $action->handle(new Request($input, $actor));
return json_decode($response->getBody());
}

View File

@@ -0,0 +1,19 @@
<?php namespace Flarum\Api\Commands;
class GenerateAccessToken
{
/**
* The ID of the user to generate an access token for.
*
* @var int
*/
public $userId;
/**
* @param int $userId The ID of the user to generate an access token for.
*/
public function __construct($userId)
{
$this->userId = $userId;
}
}

View File

@@ -0,0 +1,15 @@
<?php namespace Flarum\Api\Commands;
use Flarum\Api\AccessToken;
class GenerateAccessTokenHandler
{
public function handle(GenerateAccessToken $command)
{
$token = AccessToken::generate($command->userId);
$token->save();
return $token;
}
}

View File

@@ -1,14 +1,36 @@
<?php namespace Flarum\Api\Events;
use Flarum\Api\Serializers\Serializer;
class SerializeAttributes
{
/**
* The class doing the serializing.
*
* @var Serializer
*/
public $serializer;
/**
* The model being serialized.
*
* @var object
*/
public $model;
/**
* The serialized attributes of the resource.
*
* @var array
*/
public $attributes;
public function __construct($serializer, $model, &$attributes)
/**
* @param Serializer $serializer The class doing the serializing.
* @param object $model The model being serialized.
* @param array $attributes The serialized attributes of the resource.
*/
public function __construct(Serializer $serializer, $model, array &$attributes)
{
$this->serializer = $serializer;
$this->model = $model;

View File

@@ -1,54 +0,0 @@
<?php namespace Flarum\Api;
use Exception;
use Illuminate\Foundation\Exceptions\Handler;
use Illuminate\Http\Response;
use Illuminate\Http\JsonResponse;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Config;
class ExceptionHandler extends Handler
{
/**
* A list of the exception types that should not be reported.
*
* @var array
*/
protected $dontReport = [
'Symfony\Component\HttpKernel\Exception\HttpException'
];
/**
* Render an exception into an HTTP response.
*
* @param \Illuminate\Http\Request $request
* @param \Exception $e
* @return \Illuminate\Http\Response
*/
public function render($request, Exception $e)
{
if ($request->is('api/*')) {
$error = [];
if (Config::get('app.debug')) {
$error['code'] = (new \ReflectionClass($e))->getShortName();
}
if ($detail = $e->getMessage()) {
$error['detail'] = $detail;
}
$statusCode = $e instanceof HttpException ? $e->getStatusCode() : 500;
if (count($error)) {
return $this->renderErrors([$error], $statusCode);
} else {
return new Response(null, $statusCode);
}
}
return parent::render($request, $e);
}
protected function renderErrors($errors, $httpCode = 500)
{
return new JsonResponse(['errors' => $errors], $httpCode);
}
}

View File

@@ -1,7 +1,7 @@
<?php namespace Flarum\Api\Middleware;
use Flarum\Core\Models\AccessToken;
use Flarum\Support\Actor;
use Flarum\Api\AccessToken;
use Illuminate\Contracts\Container\Container;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Zend\Stratigility\MiddlewareInterface;
@@ -9,20 +9,21 @@ use Zend\Stratigility\MiddlewareInterface;
class LoginWithHeader implements MiddlewareInterface
{
/**
* @var Actor
* @var Container
*/
protected $actor;
protected $app;
/**
* @var string
*/
protected $prefix = 'Token ';
// @todo rather than using a singleton, we should have our own HTTP
// Request class and store the actor on that? somehow?
public function __construct(Actor $actor)
/**
* @param Container $app
*/
public function __construct(Container $app)
{
$this->actor = $actor;
$this->app = $app;
}
/**
@@ -35,7 +36,7 @@ class LoginWithHeader implements MiddlewareInterface
($token = substr($header, strlen($this->prefix))) &&
($accessToken = AccessToken::where('id', $token)->first())
) {
$this->actor->setUser($user = $accessToken->user);
$this->app->instance('flarum.actor', $user = $accessToken->user);
$user->updateLastSeen()->save();
}

View File

@@ -1,12 +1,19 @@
<?php namespace Flarum\Api;
use Flarum\Support\Actor;
use Flarum\Core\Users\Guest;
use Flarum\Core\Users\User;
use Psr\Http\Message\ServerRequestInterface;
class Request
{
/**
* @var array
*/
public $input;
/**
* @var Guest
*/
public $actor;
/**
@@ -14,18 +21,31 @@ class Request
*/
public $http;
public function __construct(array $input, Actor $actor = null, ServerRequestInterface $http = null)
/**
* @param array $input
* @param User $actor
* @param ServerRequestInterface $http
*/
public function __construct(array $input, User $actor = null, ServerRequestInterface $http = null)
{
$this->input = $input;
$this->actor = $actor;
$this->actor = $actor ?: new Guest;
$this->http = $http;
}
/**
* @param $key
* @param null $default
* @return mixed
*/
public function get($key, $default = null)
{
return array_get($this->input, $key, $default);
}
/**
* @return array
*/
public function all()
{
return $this->input;

View File

@@ -1,6 +1,6 @@
<?php namespace Flarum\Api\Serializers;
class ActivitySerializer extends BaseSerializer
class ActivitySerializer extends Serializer
{
/**
* @inheritdoc
@@ -16,38 +16,46 @@ class ActivitySerializer extends BaseSerializer
protected static $subjectSerializers = [];
/**
* Serialize attributes of an Activity model for JSON output.
*
* @param Activity $activity The Activity model to serialize.
* @return array
* {@inheritdoc}
*/
protected function attributes($activity)
protected function getDefaultAttributes($activity)
{
$attributes = [
return [
'contentType' => $activity->type,
'time' => $activity->time->toRFC3339String()
];
return $this->extendAttributes($activity, $attributes);
}
/**
* @return callable
*/
public function user()
{
return $this->hasOne('Flarum\Api\Serializers\UserBasicSerializer');
}
/**
* @return callable
*/
public function sender()
{
return $this->hasOne('Flarum\Api\Serializers\UserBasicSerializer');
}
/**
* @return callable
*/
public function subject()
{
return $this->hasOne(function ($activity) {
return static::$subjects[$activity->type];
return static::$subjectSerializers[$activity->type];
});
}
/**
* @param $type
* @param $serializer
*/
public static function setSubjectSerializer($type, $serializer)
{
static::$subjectSerializers[$type] = $serializer;

View File

@@ -1,112 +0,0 @@
<?php namespace Flarum\Api\Serializers;
use Tobscure\JsonApi\SerializerAbstract;
use Flarum\Api\Events\SerializeAttributes;
use Flarum\Api\Events\SerializeRelationship;
use Flarum\Support\Actor;
use Illuminate\Database\Eloquent\Relations\Relation;
use Closure;
/**
* A base serializer to call Flarum events at common serialization points.
*/
abstract class BaseSerializer extends SerializerAbstract
{
public $actor;
/**
* The custom relationships on this serializer.
*
* @var array
*/
protected static $relationships = [];
public function __construct(Actor $actor, $include = null, $link = null)
{
parent::__construct($include, $link);
$this->actor = $actor;
}
/**
* Fire an event to allow custom serialization of attributes.
*
* @param mixed $model The model to serialize.
* @param array $attributes Attributes that have already been serialized.
* @return array
*/
protected function extendAttributes($model, &$attributes = [])
{
event(new SerializeAttributes($this, $model, $attributes));
return $attributes;
}
protected function relationship($serializer, $relation = null, $many = false)
{
// Get the relationship name from the stack trace.
if (is_null($relation)) {
list(, , $caller) = debug_backtrace(false, 3);
$relation = $caller['function'];
}
return function ($model, $include, $included, $links) use ($serializer, $many, $relation) {
if ($relation instanceof Closure) {
$data = $relation($model, $include);
} else {
if ($include) {
$data = $model->$relation;
} elseif ($many) {
$relationIds = $relation.'_ids';
$data = isset($model->$relationIds) ? $model->$relationIds : $model->$relation()->lists('id');
} else {
$relationId = $relation.'_id';
$data = $model->$relationId;
}
}
if ($serializer instanceof Closure) {
$serializer = $serializer($model, $data);
}
$serializer = new $serializer($this->actor, $included, $links);
return $many ? $serializer->collection($data) : $serializer->resource($data);
};
}
public function hasOne($serializer, $relation = null)
{
return $this->relationship($serializer, $relation);
}
public function hasMany($serializer, $relation = null)
{
return $this->relationship($serializer, $relation, true);
}
/**
* Add a custom relationship to the serializer.
*
* @param string $name The name of the relationship.
* @param Closure $callback The callback to execute.
* @return void
*/
public static function addRelationship($name, $callback)
{
static::$relationships[$name] = $callback;
}
/**
* Check for and execute custom relationships.
*
* @param string $name
* @param array $arguments
* @return mixed
*/
public function __call($name, $arguments)
{
if (isset(static::$relationships[$name])) {
array_unshift($arguments, $this);
return call_user_func_array(static::$relationships[$name], $arguments);
}
}
}

View File

@@ -2,20 +2,21 @@
class CurrentUserSerializer extends UserSerializer
{
protected function attributes($user)
/**
* {@inheritdoc}
*/
protected function getDefaultAttributes($user)
{
$attributes = parent::attributes($user);
$attributes = parent::getDefaultAttributes($user);
$actingUser = $this->actor->getUser();
if ($user->id === $actingUser->id) {
if ($user->id == $this->actor->id) {
$attributes += [
'readTime' => $user->read_time ? $user->read_time->toRFC3339String() : null,
'readTime' => $user->read_time ? $user->read_time->toRFC3339String() : null,
'unreadNotificationsCount' => $user->getUnreadNotificationsCount(),
'preferences' => $user->preferences
'preferences' => $user->preferences
];
}
return $this->extendAttributes($user, $attributes);
return $attributes;
}
}

View File

@@ -1,67 +1,67 @@
<?php namespace Flarum\Api\Serializers;
class DiscussionBasicSerializer extends BaseSerializer
class DiscussionBasicSerializer extends Serializer
{
protected static $relationships = [];
/**
* The resource type.
*
* @var string
* {@inheritdoc}
*/
protected $type = 'discussions';
/**
* Serialize attributes of a Discussion model for JSON output.
*
* @param Discussion $discussion The Discussion model to serialize.
* @return array
* {@inheritdoc}
*/
protected function attributes($discussion)
protected function getDefaultAttributes($discussion)
{
$attributes = [
return [
'title' => $discussion->title
];
if (count($discussion->removedPosts)) {
$attributes['removedPosts'] = $discussion->removedPosts;
}
return $this->extendAttributes($discussion, $attributes);
}
public function startUser()
/**
* @return callable
*/
protected function startUser()
{
return $this->hasOne('Flarum\Api\Serializers\UserBasicSerializer');
}
public function startPost()
/**
* @return callable
*/
protected function startPost()
{
return $this->hasOne('Flarum\Api\Serializers\PostBasicSerializer');
}
public function lastUser()
/**
* @return callable
*/
protected function lastUser()
{
return $this->hasOne('Flarum\Api\Serializers\UserBasicSerializer');
}
public function lastPost()
/**
* @return callable
*/
protected function lastPost()
{
return $this->hasOne('Flarum\Api\Serializers\PostBasicSerializer');
}
public function posts()
/**
* @return callable
*/
protected function posts()
{
return $this->hasMany('Flarum\Api\Serializers\PostSerializer');
}
public function relevantPosts()
/**
* @return callable
*/
protected function relevantPosts()
{
return $this->hasMany('Flarum\Api\Serializers\PostBasicSerializer');
}
public function addedPosts()
{
return $this->hasMany('Flarum\Api\Serializers\PostSerializer');
}
}

View File

@@ -1,34 +1,34 @@
<?php namespace Flarum\Api\Serializers;
use Flarum\Core\Discussions\Discussion;
class DiscussionSerializer extends DiscussionBasicSerializer
{
/**
* Serialize attributes of a Discussion model for JSON output.
*
* @param Discussion $discussion The Discussion model to serialize.
* @return array
* {@inheritdoc}
*/
protected function attributes($discussion)
protected function getDefaultAttributes($discussion)
{
$attributes = parent::attributes($discussion);
$user = $this->actor->getUser();
$state = $discussion->state;
$attributes += [
$attributes = parent::getDefaultAttributes($discussion) + [
'commentsCount' => (int) $discussion->comments_count,
'participantsCount' => (int) $discussion->participants_count,
'startTime' => $discussion->start_time->toRFC3339String(),
'lastTime' => $discussion->last_time ? $discussion->last_time->toRFC3339String() : null,
'lastPostNumber' => $discussion->last_post_number,
'canReply' => $discussion->can($user, 'reply'),
'canRename' => $discussion->can($user, 'rename'),
'canDelete' => $discussion->can($user, 'delete'),
'readTime' => $state && $state->read_time ? $state->read_time->toRFC3339String() : null,
'readNumber' => $state ? (int) $state->read_number : 0
'canReply' => $discussion->can($this->actor, 'reply'),
'canRename' => $discussion->can($this->actor, 'rename'),
'canDelete' => $discussion->can($this->actor, 'delete')
];
return $this->extendAttributes($discussion, $attributes);
Discussion::setStateUser($this->actor);
if ($state = $discussion->state) {
$attributes += [
'readTime' => $state->read_time ? $state->read_time->toRFC3339String() : null,
'readNumber' => (int) $state->read_number
];
}
return $attributes;
}
}

View File

@@ -1,31 +1,27 @@
<?php namespace Flarum\Api\Serializers;
class ForumSerializer extends BaseSerializer
class ForumSerializer extends Serializer
{
/**
* The resource type.
*
* @var string
* {@inheritdoc}
*/
protected $type = 'forums';
protected function id($forum)
/**
* {@inheritdoc}
*/
protected function getId($forum)
{
return 1;
}
/**
* Serialize attributes of a Forum model for JSON output.
*
* @param Forum $forum The Forum model to serialize.
* @return array
* {@inheritdoc}
*/
protected function attributes($forum)
protected function getDefaultAttributes($forum)
{
$attributes = [
return [
'title' => $forum->title
];
return $this->extendAttributes($forum, $attributes);
}
}

View File

@@ -1,30 +1,23 @@
<?php namespace Flarum\Api\Serializers;
class GroupSerializer extends BaseSerializer
class GroupSerializer extends Serializer
{
/**
* The resource type.
*
* @var string
* {@inheritdoc}
*/
protected $type = 'groups';
/**
* Serialize attributes of a Group model for JSON output.
*
* @param Group $group The Group model to serialize.
* @return array
* {@inheritdoc}
*/
protected function attributes($group)
protected function getDefaultAttributes($group)
{
$attributes = [
return [
'id' => (int) $group->id,
'nameSingular' => $group->name_singular,
'namePlural' => $group->name_plural,
'color' => $group->color,
'icon' => $group->icon,
];
return $this->extendAttributes($group, $attributes);
}
}

View File

@@ -1,11 +1,9 @@
<?php namespace Flarum\Api\Serializers;
class NotificationSerializer extends BaseSerializer
class NotificationSerializer extends Serializer
{
/**
* The resource type.
*
* @var string
* {@inheritdoc}
*/
protected $type = 'notifications';
@@ -15,44 +13,55 @@ class NotificationSerializer extends BaseSerializer
*
* @var array
*/
public static $subjects = [
'discussionRenamed' => 'Flarum\Api\Serializers\DiscussionBasicSerializer'
];
protected static $subjectSerializers = [];
/**
* Serialize attributes of an notification model for JSON output.
*
* @param Notification $notification The notification model to serialize.
* @return array
* {@inheritdoc}
*/
protected function attributes($notification)
protected function getDefaultAttributes($notification)
{
$attributes = [
'id' => (int) $notification->id,
return [
'id' => (int) $notification->id,
'contentType' => $notification->type,
'content' => $notification->data,
'time' => $notification->time->toRFC3339String(),
'isRead' => (bool) $notification->is_read,
'content' => $notification->data,
'time' => $notification->time->toRFC3339String(),
'isRead' => (bool) $notification->is_read,
'unreadCount' => $notification->unread_count
];
return $this->extendAttributes($notification, $attributes);
}
/**
* @return callable
*/
public function user()
{
return $this->hasOne('Flarum\Api\Serializers\UserBasicSerializer');
}
/**
* @return callable
*/
public function sender()
{
return $this->hasOne('Flarum\Api\Serializers\UserBasicSerializer');
}
/**
* @return callable
*/
public function subject()
{
return $this->hasOne(function ($notification) {
return static::$subjects[$notification->type];
return static::$subjectSerializers[$notification->type];
});
}
/**
* @param $type
* @param $serializer
*/
public static function setSubjectSerializer($type, $serializer)
{
static::$subjectSerializers[$type] = $serializer;
}
}

View File

@@ -1,29 +1,22 @@
<?php namespace Flarum\Api\Serializers;
class PostBasicSerializer extends BaseSerializer
class PostBasicSerializer extends Serializer
{
protected static $relationships = [];
/**
* The resource type.
*
* @var string
* {@inheritdoc}
*/
protected $type = 'posts';
/**
* Serialize attributes of a Post model for JSON output.
*
* @param Post $post The Post model to serialize.
* @return array
* {@inheritdoc}
*/
protected function attributes($post)
protected function getDefaultAttributes($post)
{
$attributes = [
'id' => (int) $post->id,
'number' => (int) $post->number,
'time' => $post->time->toRFC3339String(),
'contentType' => $post->type
'id' => (int) $post->id,
'number' => (int) $post->number,
'time' => $post->time->toRFC3339String(),
'contentType' => $post->type
];
if ($post->type === 'comment') {
@@ -32,14 +25,20 @@ class PostBasicSerializer extends BaseSerializer
$attributes['content'] = $post->content;
}
return $this->extendAttributes($post, $attributes);
return $attributes;
}
/**
* @return callable
*/
public function user()
{
return $this->hasOne('Flarum\Api\Serializers\UserBasicSerializer');
}
/**
* @return callable
*/
public function discussion()
{
return $this->hasOne('Flarum\Api\Serializers\DiscussionBasicSerializer');

View File

@@ -3,22 +3,19 @@
class PostSerializer extends PostBasicSerializer
{
/**
* Serialize attributes of a Post model for JSON output.
*
* @param Post $post The Post model to serialize.
* @return array
* {@inheritdoc}
*/
protected function attributes($post)
protected function getDefaultAttributes($post)
{
$attributes = parent::attributes($post);
$user = $this->actor->getUser();
$attributes = parent::getDefaultAttributes($post);
unset($attributes['content']);
$canEdit = $post->can($user, 'edit');
$canEdit = $post->can($this->actor, 'edit');
if ($post->type === 'comment') {
$attributes['contentHtml'] = $post->content_html;
if ($canEdit) {
$attributes['content'] = $post->content;
}
@@ -37,27 +34,39 @@ class PostSerializer extends PostBasicSerializer
$attributes += [
'canEdit' => $canEdit,
'canDelete' => $post->can($user, 'delete')
'canDelete' => $post->can($this->actor, 'delete')
];
return $this->extendAttributes($post, $attributes);
return $attributes;
}
/**
* @return callable
*/
public function user()
{
return $this->hasOne('Flarum\Api\Serializers\UserSerializer');
}
/**
* @return callable
*/
public function discussion()
{
return $this->hasOne('Flarum\Api\Serializers\DiscussionSerializer');
}
/**
* @return callable
*/
public function editUser()
{
return $this->hasOne('Flarum\Api\Serializers\UserSerializer');
}
/**
* @return callable
*/
public function hideUser()
{
return $this->hasOne('Flarum\Api\Serializers\UserSerializer');

View File

@@ -0,0 +1,178 @@
<?php namespace Flarum\Api\Serializers;
use BadMethodCallException;
use Closure;
use Flarum\Core\Users\User;
use Tobscure\JsonApi\SerializerAbstract;
use Flarum\Api\Events\SerializeAttributes;
abstract class Serializer extends SerializerAbstract
{
/**
* @var User
*/
public $actor;
/**
* An array of custom relation methods, grouped by subclass.
*
* @var array
*/
protected static $relationMethods = [];
/**
* @param User $actor
* @param array|null $include
* @param array|null $link
*/
public function __construct(User $actor, $include = null, $link = null)
{
parent::__construct($include, $link);
$this->actor = $actor;
}
/**
* {@inheritdoc}
*/
protected function getAttributes($model)
{
$attributes = $this->getDefaultAttributes($model);
event(new SerializeAttributes($this, $model, $attributes));
return $attributes;
}
/**
* Get the default set of serialized attributes for a model.
*
* @param $model
* @return array
*/
abstract protected function getDefaultAttributes($model);
/**
* Get a closure that returns a Collection/Resource representing a relation.
*
* @param string|Closure $serializer The name of the serializer, or a
* Closure returning the name of the serializer, to use for the related
* items.
* @param string|Closure|null $relation If a string is provided, it will be
* used to retrieve the relation data from the model:
* - If the relation is being included, the relation will be accessed
* as a property on the model.
* - If the relation is not being included and is a to-many relation, a
* list of IDs will be accessed as a property on the model with the
* suffix '_ids', otherwise by querying the relation method.
* - If the relation is not being included and is a to-one relation,
* the ID will be accessed as a property on the model with the suffix
* '_id'.
* If a closure is provided, it will be passed the model and
* whether or not the relation is being included. It is expected to
* return the relation data.
* @param bool $many Whether or not this is a to-many relation.
* @return callable
*/
protected function getRelationship($serializer, $relation = null, $many = false)
{
// If no relationship name was provided, we can guess it from the
// stack trace. The assumes that one of the hasOne or hasMany methods
// was called from directly inside a serializer method.
if (is_null($relation)) {
list(, , $caller) = debug_backtrace(false, 3);
$relation = $caller['function'];
}
return function ($model, $include, $included, $links) use ($serializer, $many, $relation) {
// If the passed relation was a closure, we can let that take care
// of retrieving the relation data from the model. Otherwise, we
// need to get the data from the model itself, using the relation
// name provided.
if ($relation instanceof Closure) {
$data = $relation($model, $include);
} else {
if ($include) {
$data = $model->$relation;
} elseif ($many) {
$relationIds = $relation.'_ids';
$data = isset($model->$relationIds) ? $model->$relationIds : $model->$relation()->lists('id');
} else {
$relationId = $relation.'_id';
$data = $model->$relationId;
}
}
// If the passed serializer was a closure, we'll need to run
// that in order to find out which serializer class to instantiate.
// This is useful for polymorphic relations.
if ($serializer instanceof Closure) {
$serializer = $serializer($model, $data);
}
/** @var \Tobscure\JsonApi\SerializerInterface $serializer */
$serializer = new $serializer($this->actor, $included, $links);
return $many ? $serializer->collection($data) : $serializer->resource($data);
};
}
/**
* Get a closure that returns a Resource representing a relation.
*
* @param string $serializer
* @param string|Closure|null $relation
* @see Serializer::getRelationship()
* @return callable
*/
public function hasOne($serializer, $relation = null)
{
return $this->getRelationship($serializer, $relation);
}
/**
* Get a closure that returns a Collection representing a relation.
*
* @param string $serializer
* @param string|Closure|null $relation
* @see Serializer::getRelationship()
* @return callable
*/
public function hasMany($serializer, $relation = null)
{
return $this->getRelationship($serializer, $relation, true);
}
/**
* Add a custom relation to the model.
*
* @param string $name The name of the relation.
* @param callable $callback The callback to execute. This should return a
* relation closure {@see Serializer::getRelationship()}
*/
public static function setRelationMethod($name, callable $callback)
{
static::$relationMethods[get_called_class()][$name] = $callback;
}
/**
* Check for and execute custom relationships.
*
* @param string $method
* @param array $parameters
* @return mixed
* @throws BadMethodCallException
*/
public function __call($method, $parameters)
{
if (isset(static::$relationMethods[$method])) {
array_unshift($parameters, $this);
return call_user_func_array(static::$relationMethods[$method], $parameters);
}
$className = get_class($this);
throw new BadMethodCallException("Call to undefined method {$className}::{$method}()");
}
}

View File

@@ -1,30 +1,26 @@
<?php namespace Flarum\Api\Serializers;
class UserBasicSerializer extends BaseSerializer
class UserBasicSerializer extends Serializer
{
/**
* The resource type.
*
* @var string
* {@inheritdoc}
*/
protected $type = 'users';
/**
* Serialize attributes of a User model for JSON output.
*
* @param User $user The User model to serialize.
* @return array
* {@inheritdoc}
*/
protected function attributes($user)
protected function getDefaultAttributes($user)
{
$attributes = [
return [
'username' => $user->username,
'avatarUrl' => $user->avatar_url
];
return $this->extendAttributes($user, $attributes);
}
/**
* @return callable
*/
protected function groups()
{
return $this->hasMany('Flarum\Api\Serializers\GroupSerializer');

View File

@@ -3,17 +3,13 @@
class UserSerializer extends UserBasicSerializer
{
/**
* Serialize attributes of a User model for JSON output.
*
* @param User $user The User model to serialize.
* @return array
* {@inheritdoc}
*/
protected function attributes($user)
protected function getDefaultAttributes($user)
{
$attributes = parent::attributes($user);
$attributes = parent::getDefaultAttributes($user);
$actingUser = $this->actor->getUser();
$canEdit = $user->can($actingUser, 'edit');
$canEdit = $user->can($this->actor, 'edit');
$attributes += [
'bioHtml' => $user->bio_html,
@@ -21,10 +17,10 @@ class UserSerializer extends UserBasicSerializer
'discussionsCount' => (int) $user->discussions_count,
'commentsCount' => (int) $user->comments_count,
'canEdit' => $canEdit,
'canDelete' => $user->can($actingUser, 'delete'),
'canDelete' => $user->can($this->actor, 'delete'),
];
if ($user->preference('discloseOnline')) {
if ($user->getPreference('discloseOnline')) {
$attributes += [
'lastSeenTime' => $user->last_seen_time ? $user->last_seen_time->toRFC3339String() : null
];
@@ -39,6 +35,6 @@ class UserSerializer extends UserBasicSerializer
];
}
return $this->extendAttributes($user, $attributes);
return $attributes;
}
}