Update APIs

This commit is contained in:
Toby Zerner 2015-06-18 12:46:02 +09:30
parent d4f15858ca
commit 59736524e0
2 changed files with 131 additions and 121 deletions

View File

@ -22,4 +22,21 @@ class Tag extends Model
{
return $this->belongsTo('Flarum\Core\Models\Discussion', 'last_discussion_id');
}
public static function getVisibleTo($user)
{
static $tags;
if (!$tags) {
$tags = static::all();
}
$ids = [];
foreach ($tags as $tag) {
if (! $tag->is_restricted || $user->hasPermission('tag'.$tag->id.'.view')) {
$ids[] = $tag->id;
}
}
return $ids;
}
}

View File

@ -1,132 +1,12 @@
<?php namespace Flarum\Tags;
use Flarum\Support\ServiceProvider;
use Flarum\Extend\ForumAssets;
use Flarum\Extend\EventSubscribers;
use Flarum\Extend\Relationship;
use Flarum\Extend\SerializeRelationship;
use Flarum\Extend\ApiInclude;
use Flarum\Extend\ApiLink;
use Flarum\Extend\Permission;
use Flarum\Extend\DiscussionGambit;
use Flarum\Extend\PostType;
use Flarum\Extend;
use Flarum\Core\Models\Discussion;
use Flarum\Core\Models\Post;
use Flarum\Core\Models\User;
class TagsServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application events.
*
* @return void
*/
public function boot()
{
$this->extend([
new ForumAssets([
__DIR__.'/../js/dist/extension.js',
__DIR__.'/../less/extension.less'
]),
new EventSubscribers([
'Flarum\Tags\Handlers\DiscussionTaggedNotifier',
'Flarum\Tags\Handlers\TagSaver',
'Flarum\Tags\Handlers\TagLoader'
]),
new Relationship('Flarum\Core\Models\Discussion', 'tags', function ($model) {
return $model->belongsToMany('Flarum\Tags\Tag', 'discussions_tags');
}),
new SerializeRelationship('Flarum\Api\Serializers\DiscussionBasicSerializer', 'hasMany', 'tags', 'Flarum\Tags\TagSerializer'),
new ApiInclude(['discussions.index', 'discussions.show'], 'tags', true),
new SerializeRelationship('Flarum\Api\Serializers\ForumSerializer', 'hasMany', 'tags', 'Flarum\Tags\TagSerializer'),
new ApiInclude(['forum.show'], ['tags', 'tags.lastDiscussion'], true),
new ApiLink(['forum.show'], ['tags.parent'], true),
(new Permission('discussion.tag'))
->serialize(),
// ->grant(function ($grant, $user) {
// $grant->where('start_user_id', $user->id);
// // @todo add limitations to time etc. according to a config setting
// }),
new DiscussionGambit('Flarum\Tags\TagGambit'),
new PostType('Flarum\Tags\DiscussionTaggedPost')
]);
Tag::scopeVisible(function ($query, User $user) {
$query->whereIn('id', $this->getTagsWithPermission($user, 'view'));
});
Tag::allow('startDiscussion', function (Tag $tag, User $user) {
if (! $tag->is_restricted || $user->hasPermission('tag'.$tag->id.'.startDiscussion')) {
return true;
}
});
Discussion::scopeVisible(function ($query, User $user) {
$query->whereNotExists(function ($query) use ($user) {
return $query->select(app('db')->raw(1))
->from('discussions_tags')
->whereNotIn('tag_id', $this->getTagsWithPermission($user, 'view'))
->whereRaw('discussion_id = discussions.id');
});
});
Discussion::allow('*', function (Discussion $discussion, User $user, $action) {
$tags = $discussion->getRelation('tags');
if (! count($tags)) {
return;
}
$restricted = true;
// If the discussion has a tag that has been restricted, and the user
// has this permission for that tag, then they are allowed. If the
// discussion only has tags that have been restricted, then the user
// *must* have permission for at least one of them. Otherwise, inherit
// global permissions.
foreach ($tags as $tag) {
if ($tag->is_restricted) {
if ($user->hasPermission('tag'.$tag->id.'.discussion.'.$action)) {
return true;
}
} else {
$restricted = false;
}
}
if ($restricted) {
return false;
}
});
Post::allow('*', function (Post $post, User $user, $action) {
return $post->discussion->can($user, $action.'Posts');
});
}
protected function getTagsWithPermission($user, $permission) {
static $tags;
if (!$tags) $tags = Tag::all();
$ids = [];
foreach ($tags as $tag) {
if (! $tag->is_restricted || $user->hasPermission('tag'.$tag->id.'.'.$permission)) {
$ids[] = $tag->id;
}
}
return $ids;
}
/**
* Register the service provider.
*
@ -139,4 +19,117 @@ class TagsServiceProvider extends ServiceProvider
'Flarum\Tags\EloquentTagRepository'
);
}
/**
* Bootstrap the application events.
*
* @return void
*/
public function boot()
{
$this->extend([
(new Extend\ForumClient())
->assets([
__DIR__.'/../js/dist/extension.js',
__DIR__.'/../less/extension.less'
]),
(new Extend\Model('Flarum\Tags\Tag'))
// Hide tags that the user doesn't have permission to see.
->scopeVisible(function ($query, User $user) {
$query->whereIn('id', Tag::getVisibleTo($user));
})
// Allow the user to start discussions in tags which aren't
// restricted, or for which the user has explicitly been granted
// permission.
->allow('startDiscussion', function (Tag $tag, User $user) {
if (! $tag->is_restricted || $user->hasPermission('tag'.$tag->id.'.startDiscussion')) {
return true;
}
}),
// Expose the complete tag list to clients by adding it as a
// relationship to the /api/forum endpoint. Since the Forum model
// doesn't actually have a tags relationship, we will manually
// load and assign the tags data to it using an event listener.
(new Extend\ApiSerializer('Flarum\Api\Serializers\ForumSerializer'))
->hasMany('tags', 'Flarum\Tags\TagSerializer'),
(new Extend\ApiAction('Flarum\Api\Actions\Forum\ShowAction'))
->addInclude('tags')
->addInclude('tags.lastDiscussion')
->addLink('tags.parent'),
new Extend\EventSubscriber('Flarum\Tags\Handlers\TagLoader'),
// Extend the Discussion model and API: add the tags relationship
// and modify permissions.
(new Extend\Model('Flarum\Core\Models\Discussion'))
->belongsToMany('tags', 'Flarum\Tags\Tag', 'discussions_tags')
// Hide discussions which have tags that the user is not allowed
// to see.
->scopeVisible(function ($query, User $user) {
$query->whereNotExists(function ($query) use ($user) {
return $query->select(app('db')->raw(1))
->from('discussions_tags')
->whereNotIn('tag_id', Tag::getVisibleTo($user))
->whereRaw('discussion_id = discussions.id');
});
})
// Wrap all discussion permission checks with some logic
// pertaining to the discussion's tags. If the discussion has a
// tag that has been restricted, and the user has this
// permission for that tag, then they are allowed. If the
// discussion only has tags that have been restricted, then the
// user *must* have permission for at least one of them.
->allow('*', function (Discussion $discussion, User $user, $action) {
$tags = $discussion->getRelation('tags');
if (count($tags)) {
$restricted = true;
foreach ($tags as $tag) {
if ($tag->is_restricted) {
if ($user->hasPermission('tag'.$tag->id.'.discussion.'.$action)) {
return true;
}
} else {
$restricted = false;
}
}
if ($restricted) {
return false;
}
}
}),
(new Extend\ApiSerializer('Flarum\Api\Serializers\DiscussionBasicSerializer'))
->hasMany('tags', 'Flarum\Tags\TagSerializer')
->attributes(function (&$attributes, $discussion, $user) {
$attributes['canTag'] = $discussion->can($user, 'tag');
}),
(new Extend\ApiAction([
'Flarum\Api\Actions\Discussions\IndexAction',
'Flarum\Api\Actions\Discussions\ShowAction'
]))
->addInclude('tags'),
// Add an event subscriber so that tags data is persisted when
// saving a discussion.
new Extend\EventSubscriber('Flarum\Tags\Handlers\TagSaver'),
// Add a gambit that allows filtering discussions by tag(s).
new Extend\DiscussionGambit('Flarum\Tags\TagGambit'),
// Add a new post type which indicates when a discussion's tags were
// changed.
new Extend\PostType('Flarum\Tags\DiscussionTaggedPost'),
new Extend\EventSubscriber('Flarum\Tags\Handlers\DiscussionTaggedNotifier')
]);
}
}