Use new extenders (#34)

This commit is contained in:
Sami Mazouz 2020-12-08 17:43:56 +01:00 committed by GitHub
parent 46fcc1c18b
commit c6e14394fd
8 changed files with 261 additions and 221 deletions

View File

@ -7,17 +7,28 @@
* LICENSE file that was distributed with this source code.
*/
use Flarum\Api\Event\Serializing;
use Flarum\Api\Controller\AbstractSerializeController;
use Flarum\Api\Controller\ListPostsController;
use Flarum\Api\Controller\ShowDiscussionController;
use Flarum\Api\Controller\ShowPostController;
use Flarum\Api\Serializer\CurrentUserSerializer;
use Flarum\Api\Serializer\ForumSerializer;
use Flarum\Api\Serializer\PostSerializer;
use Flarum\Extend;
use Flarum\Flags\AddCanFlagAttribute;
use Flarum\Flags\AddFlagsApiAttributes;
use Flarum\Flags\AddNewFlagCountAttribute;
use Flarum\Flags\Api\Controller\CreateFlagController;
use Flarum\Flags\Api\Controller\DeleteFlagsController;
use Flarum\Flags\Api\Controller\ListFlagsController;
use Flarum\Flags\Api\Serializer\FlagSerializer;
use Flarum\Flags\Flag;
use Flarum\Flags\Listener;
use Flarum\Flags\PrepareFlagsApiData;
use Flarum\Forum\Content\AssertRegistered;
use Flarum\Post\Event\Deleted;
use Flarum\Post\Post;
use Flarum\User\User;
use Illuminate\Contracts\Events\Dispatcher;
return [
(new Extend\Frontend('forum'))
@ -39,11 +50,33 @@ return [
(new Extend\Model(Post::class))
->hasMany('flags', Flag::class, 'post_id'),
(new Extend\ApiSerializer(PostSerializer::class))
->hasMany('flags', FlagSerializer::class)
->attribute('canFlag', AddCanFlagAttribute::class),
(new Extend\ApiSerializer(CurrentUserSerializer::class))
->attribute('newFlagCount', AddNewFlagCountAttribute::class),
(new Extend\ApiSerializer(ForumSerializer::class))
->mutate(AddFlagsApiAttributes::class),
(new Extend\ApiController(ShowDiscussionController::class))
->addInclude(['posts.flags', 'posts.flags.user']),
(new Extend\ApiController(ListPostsController::class))
->addInclude(['flags', 'flags.user']),
(new Extend\ApiController(ShowPostController::class))
->addInclude(['flags', 'flags.user']),
(new Extend\ApiController(AbstractSerializeController::class))
->prepareDataForSerialization(PrepareFlagsApiData::class),
(new Extend\Settings())
->serializeToForum('guidelinesUrl', 'flarum-flags.guidelines_url'),
(new Extend\Event())
->listen(Deleted::class, Listener\DeleteFlags::class),
new Extend\Locales(__DIR__.'/locale'),
function (Dispatcher $events) {
$events->listen(Serializing::class, Listener\AddFlagsApiAttributes::class);
$events->subscribe(Listener\AddPostFlagsRelationship::class);
},
];

View File

@ -0,0 +1,46 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Flags;
use Flarum\Api\Serializer\PostSerializer;
use Flarum\Post\Post;
use Flarum\Settings\SettingsRepositoryInterface;
use Flarum\User\User;
class AddCanFlagAttribute
{
/**
* @var SettingsRepositoryInterface
*/
protected $settings;
/**
* @param SettingsRepositoryInterface $settings
*/
public function __construct(SettingsRepositoryInterface $settings)
{
$this->settings = $settings;
}
public function __invoke(PostSerializer $serializer, Post $post)
{
return $serializer->getActor()->can('flag', $post) && $this->checkFlagOwnPostSetting($serializer->getActor(), $post);
}
protected function checkFlagOwnPostSetting(User $actor, Post $post): bool
{
if ($actor->id === $post->user_id) {
// If $actor is the post author, check to see if the setting is enabled
return (bool) $this->settings->get('flarum-flags.can_flag_own');
}
// $actor is not the post author
return true;
}
}

View File

@ -0,0 +1,52 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Flags;
use Flarum\Api\Serializer\ForumSerializer;
use Flarum\Settings\SettingsRepositoryInterface;
use Flarum\User\User;
class AddFlagsApiAttributes
{
/**
* @var SettingsRepositoryInterface
*/
protected $settings;
/**
* @param SettingsRepositoryInterface $settings
*/
public function __construct(SettingsRepositoryInterface $settings)
{
$this->settings = $settings;
}
public function __invoke(ForumSerializer $serializer)
{
$attributes = [
'canViewFlags' => $serializer->getActor()->hasPermissionLike('discussion.viewFlags')
];
if ($attributes['canViewFlags']) {
$attributes['flagCount'] = (int) $this->getFlagCount($serializer->getActor());
}
return $attributes;
}
/**
* @param User $actor
* @return int
*/
protected function getFlagCount(User $actor)
{
return Flag::whereVisibleTo($actor)->distinct()->count('flags.post_id');
}
}

View File

@ -0,0 +1,36 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Flags;
use Flarum\Api\Serializer\CurrentUserSerializer;
use Flarum\User\User;
class AddNewFlagCountAttribute
{
public function __invoke(CurrentUserSerializer $serializer, User $user)
{
return (int) $this->getNewFlagCount($user);
}
/**
* @param User $actor
* @return int
*/
protected function getNewFlagCount(User $actor)
{
$query = Flag::whereVisibleTo($actor);
if ($time = $actor->read_flags_at) {
$query->where('flags.created_at', '>', $time);
}
return $query->distinct()->count('flags.post_id');
}
}

View File

@ -1,90 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Flags\Listener;
use Flarum\Api\Event\Serializing;
use Flarum\Api\Serializer\CurrentUserSerializer;
use Flarum\Api\Serializer\ForumSerializer;
use Flarum\Api\Serializer\PostSerializer;
use Flarum\Flags\Flag;
use Flarum\Post\Post;
use Flarum\Settings\SettingsRepositoryInterface;
use Flarum\User\User;
class AddFlagsApiAttributes
{
/**
* @var SettingsRepositoryInterface
*/
protected $settings;
/**
* @param SettingsRepositoryInterface $settings
*/
public function __construct(SettingsRepositoryInterface $settings)
{
$this->settings = $settings;
}
public function handle(Serializing $event)
{
if ($event->isSerializer(ForumSerializer::class)) {
$event->attributes['canViewFlags'] = $event->actor->hasPermissionLike('discussion.viewFlags');
if ($event->attributes['canViewFlags']) {
$event->attributes['flagCount'] = (int) $this->getFlagCount($event->actor);
}
$event->attributes['guidelinesUrl'] = $this->settings->get('flarum-flags.guidelines_url');
}
if ($event->isSerializer(CurrentUserSerializer::class)) {
$event->attributes['newFlagCount'] = (int) $this->getNewFlagCount($event->model);
}
if ($event->isSerializer(PostSerializer::class)) {
$event->attributes['canFlag'] = $event->actor->can('flag', $event->model) && $this->checkFlagOwnPostSetting($event->actor, $event->model);
}
}
/**
* @param User $actor
* @return int
*/
protected function getFlagCount(User $actor)
{
return Flag::whereVisibleTo($actor)->distinct()->count('flags.post_id');
}
/**
* @param User $actor
* @return int
*/
protected function getNewFlagCount(User $actor)
{
$query = Flag::whereVisibleTo($actor);
if ($time = $actor->read_flags_at) {
$query->where('flags.created_at', '>', $time);
}
return $query->distinct()->count('flags.post_id');
}
protected function checkFlagOwnPostSetting(User $actor, Post $post): bool
{
if ($actor->id === $post->user_id) {
// If $actor is the post author, check to see if the setting is enabled
return (bool) $this->settings->get('flarum-flags.can_flag_own');
}
// $actor is not the post author
return true;
}
}

View File

@ -1,123 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Flags\Listener;
use Flarum\Api\Controller;
use Flarum\Api\Event\WillGetData;
use Flarum\Api\Event\WillSerializeData;
use Flarum\Api\Serializer\PostSerializer;
use Flarum\Event\GetApiRelationship;
use Flarum\Flags\Api\Controller\CreateFlagController;
use Flarum\Flags\Api\Serializer\FlagSerializer;
use Flarum\Post\Event\Deleted;
use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Database\Eloquent\Collection;
class AddPostFlagsRelationship
{
/**
* @param Dispatcher $events
*/
public function subscribe(Dispatcher $events)
{
$events->listen(Deleted::class, [$this, 'postWasDeleted']);
$events->listen(GetApiRelationship::class, [$this, 'getApiRelationship']);
$events->listen(WillGetData::class, [$this, 'includeFlagsRelationship']);
$events->listen(WillSerializeData::class, [$this, 'prepareApiData']);
}
/**
* @param Deleted $event
*/
public function postWasDeleted(Deleted $event)
{
$event->post->flags()->delete();
}
/**
* @param GetApiRelationship $event
* @return \Tobscure\JsonApi\Relationship|null
*/
public function getApiRelationship(GetApiRelationship $event)
{
if ($event->isRelationship(PostSerializer::class, 'flags')) {
return $event->serializer->hasMany($event->model, FlagSerializer::class, 'flags');
}
}
/**
* @param WillGetData $event
*/
public function includeFlagsRelationship(WillGetData $event)
{
if ($event->isController(Controller\ShowDiscussionController::class)) {
$event->addInclude([
'posts.flags',
'posts.flags.user'
]);
}
if ($event->isController(Controller\ListPostsController::class)
|| $event->isController(Controller\ShowPostController::class)) {
$event->addInclude([
'flags',
'flags.user'
]);
}
}
/**
* @param WillSerializeData $event
*/
public function prepareApiData(WillSerializeData $event)
{
// For any API action that allows the 'flags' relationship to be
// included, we need to preload this relationship onto the data (Post
// models) so that we can selectively expose only the flags that the
// user has permission to view.
if ($event->isController(Controller\ShowDiscussionController::class)) {
if ($event->data->relationLoaded('posts')) {
$posts = $event->data->getRelation('posts');
}
}
if ($event->isController(Controller\ListPostsController::class)) {
$posts = $event->data->all();
}
if ($event->isController(Controller\ShowPostController::class)) {
$posts = [$event->data];
}
if ($event->isController(CreateFlagController::class)) {
$posts = [$event->data->post];
}
if (isset($posts)) {
$actor = $event->request->getAttribute('actor');
$postsWithPermission = [];
foreach ($posts as $post) {
if (is_object($post)) {
$post->setRelation('flags', null);
if ($actor->can('viewFlags', $post->discussion)) {
$postsWithPermission[] = $post;
}
}
}
if (count($postsWithPermission)) {
(new Collection($postsWithPermission))
->load('flags', 'flags.user');
}
}
}
}

View File

@ -0,0 +1,23 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Flags\Listener;
use Flarum\Post\Event\Deleted;
class DeleteFlags
{
/**
* @param Deleted $event
*/
public function handle(Deleted $event)
{
$event->post->flags()->delete();
}
}

View File

@ -0,0 +1,63 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Flags;
use Flarum\Api\Controller;
use Flarum\Flags\Api\Controller\CreateFlagController;
use Illuminate\Database\Eloquent\Collection;
use Psr\Http\Message\ServerRequestInterface;
class PrepareFlagsApiData
{
public function __invoke(Controller\AbstractSerializeController $controller, $data, ServerRequestInterface $request)
{
// For any API action that allows the 'flags' relationship to be
// included, we need to preload this relationship onto the data (Post
// models) so that we can selectively expose only the flags that the
// user has permission to view.
if ($controller instanceof Controller\ShowDiscussionController) {
if ($data->relationLoaded('posts')) {
$posts = $data->getRelation('posts');
}
}
if ($controller instanceof Controller\ListPostsController) {
$posts = $data->all();
}
if ($controller instanceof Controller\ShowPostController) {
$posts = [$data];
}
if ($controller instanceof CreateFlagController) {
$posts = [$data->post];
}
if (isset($posts)) {
$actor = $request->getAttribute('actor');
$postsWithPermission = [];
foreach ($posts as $post) {
if (is_object($post)) {
$post->setRelation('flags', null);
if ($actor->can('viewFlags', $post->discussion)) {
$postsWithPermission[] = $post;
}
}
}
if (count($postsWithPermission)) {
(new Collection($postsWithPermission))
->load('flags', 'flags.user');
}
}
}
}