mirror of
https://github.com/flarum/framework.git
synced 2024-12-02 06:53:47 +08:00
Per-tag permissions!
Pretty easy to implement with the groundwork I’ve done for permissions. (All the logic is in TagsServiceProvider currently)
This commit is contained in:
parent
f3f0684eee
commit
5345a1ef9e
|
@ -11,7 +11,7 @@ export default class TagDiscussionModal extends FormModal {
|
|||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.tags = sortTags(app.store.all('tags'));
|
||||
this.tags = sortTags(app.store.all('tags').filter(tag => tag.canStartDiscussion()));
|
||||
|
||||
this.selected = m.prop([]);
|
||||
if (this.props.selectedTags) {
|
||||
|
@ -28,6 +28,8 @@ export default class TagDiscussionModal extends FormModal {
|
|||
}
|
||||
|
||||
addTag(tag) {
|
||||
if (!tag.canStartDiscussion()) return;
|
||||
|
||||
var selected = this.selected();
|
||||
var parent = tag.parent();
|
||||
if (parent) {
|
||||
|
|
|
@ -21,4 +21,6 @@ Tag.prototype.discussionsCount = Model.prop('discussionsCount');
|
|||
Tag.prototype.lastTime = Model.prop('lastTime', Model.date);
|
||||
Tag.prototype.lastDiscussion = Model.one('lastDiscussion');
|
||||
|
||||
Tag.prototype.canStartDiscussion = Model.prop('canStartDiscussion');
|
||||
|
||||
export default Tag;
|
||||
|
|
|
@ -26,6 +26,7 @@ class CreateTagsTable extends Migration
|
|||
$table->integer('position')->nullable();
|
||||
$table->integer('parent_id')->unsigned()->nullable();
|
||||
$table->string('default_sort', 50)->nullable();
|
||||
$table->boolean('is_restricted')->default(0);
|
||||
|
||||
$table->integer('discussions_count')->unsigned()->default(0);
|
||||
$table->integer('last_time')->unsigned()->nullable();
|
||||
|
|
25
extensions/tags/src/Handlers/TagLoader.php
Executable file
25
extensions/tags/src/Handlers/TagLoader.php
Executable file
|
@ -0,0 +1,25 @@
|
|||
<?php namespace Flarum\Tags\Handlers;
|
||||
|
||||
use Flarum\Api\Events\WillRespond;
|
||||
use Flarum\Api\Actions\Forum\ShowAction as ForumShowAction;
|
||||
use Flarum\Tags\Tag;
|
||||
|
||||
class TagLoader
|
||||
{
|
||||
public function subscribe($events)
|
||||
{
|
||||
$events->listen('Flarum\Api\Events\WillRespond', __CLASS__.'@whenWillRespond');
|
||||
}
|
||||
|
||||
public function whenWillRespond(WillRespond $event)
|
||||
{
|
||||
if ($event->action instanceof ForumShowAction) {
|
||||
$forum = $event->data;
|
||||
|
||||
$query = Tag::whereVisibleTo($event->request->actor->getUser());
|
||||
|
||||
$forum->tags = $query->with('lastDiscussion')->get();
|
||||
$forum->tags_ids = $forum->tags->lists('id');
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +1,11 @@
|
|||
<?php namespace Flarum\Tags\Handlers;
|
||||
|
||||
use Flarum\Tags\Tag;
|
||||
use Flarum\Tags\Events\DiscussionWasTagged;
|
||||
use Flarum\Core\Events\DiscussionWillBeSaved;
|
||||
use Flarum\Core\Events\DiscussionWasDeleted;
|
||||
use Flarum\Core\Models\Discussion;
|
||||
use Flarum\Core\Exceptions\PermissionDeniedException;
|
||||
|
||||
class TagSaver
|
||||
{
|
||||
|
@ -25,6 +27,13 @@ class TagSaver
|
|||
$newTagIds[] = (int) $link['id'];
|
||||
}
|
||||
|
||||
$newTags = Tag::whereIn('id', $newTagIds);
|
||||
foreach ($newTags as $tag) {
|
||||
if (! $tag->can($user, 'startDiscussion')) {
|
||||
throw new PermissionDeniedException;
|
||||
}
|
||||
}
|
||||
|
||||
$oldTags = [];
|
||||
|
||||
if ($discussion->exists) {
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
<?php namespace Flarum\Tags;
|
||||
|
||||
use Flarum\Core\Models\Model;
|
||||
use Flarum\Core\Support\Locked;
|
||||
use Flarum\Core\Support\VisibleScope;
|
||||
|
||||
class Tag extends Model
|
||||
{
|
||||
use Locked;
|
||||
use VisibleScope;
|
||||
|
||||
protected $table = 'tags';
|
||||
|
||||
protected $dates = ['last_time'];
|
||||
|
|
|
@ -19,6 +19,8 @@ class TagSerializer extends BaseSerializer
|
|||
*/
|
||||
protected function attributes($tag)
|
||||
{
|
||||
$user = $this->actor->getUser();
|
||||
|
||||
$attributes = [
|
||||
'name' => $tag->name,
|
||||
'description' => $tag->description,
|
||||
|
@ -31,7 +33,8 @@ class TagSerializer extends BaseSerializer
|
|||
'position' => $tag->position === null ? null : (int) $tag->position,
|
||||
'defaultSort' => $tag->default_sort,
|
||||
'isChild' => (bool) $tag->parent_id,
|
||||
'lastTime' => $tag->last_time ? $tag->last_time->toRFC3339String() : null
|
||||
'lastTime' => $tag->last_time ? $tag->last_time->toRFC3339String() : null,
|
||||
'canStartDiscussion' => $tag->can($user, 'startDiscussion')
|
||||
];
|
||||
|
||||
return $this->extendAttributes($tag, $attributes);
|
||||
|
@ -44,6 +47,6 @@ class TagSerializer extends BaseSerializer
|
|||
|
||||
protected function lastDiscussion()
|
||||
{
|
||||
return $this->hasOne('Flarum\Api\Serializers\DiscussionSerializer');
|
||||
return $this->hasOne('Flarum\Api\Serializers\DiscussionBasicSerializer');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,9 +6,13 @@ 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\Core\Models\Discussion;
|
||||
use Flarum\Core\Models\Post;
|
||||
use Flarum\Core\Models\User;
|
||||
|
||||
class TagsServiceProvider extends ServiceProvider
|
||||
{
|
||||
|
@ -27,7 +31,8 @@ class TagsServiceProvider extends ServiceProvider
|
|||
|
||||
new EventSubscribers([
|
||||
'Flarum\Tags\Handlers\DiscussionTaggedNotifier',
|
||||
'Flarum\Tags\Handlers\TagSaver'
|
||||
'Flarum\Tags\Handlers\TagSaver',
|
||||
'Flarum\Tags\Handlers\TagLoader'
|
||||
]),
|
||||
|
||||
new Relationship('Flarum\Core\Models\Discussion', 'tags', function ($model) {
|
||||
|
@ -38,25 +43,88 @@ class TagsServiceProvider extends ServiceProvider
|
|||
|
||||
new ApiInclude(['discussions.index', 'discussions.show'], 'tags', true),
|
||||
|
||||
new Relationship('Flarum\Core\Models\Forum', 'tags', function ($model) {
|
||||
return Tag::query();
|
||||
}),
|
||||
|
||||
new SerializeRelationship('Flarum\Api\Serializers\ForumSerializer', 'hasMany', 'tags', 'Flarum\Tags\TagSerializer'),
|
||||
|
||||
new ApiInclude(['forum.show'], ['tags', 'tags.parent', 'tags.lastDiscussion'], true),
|
||||
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
|
||||
}),
|
||||
->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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue
Block a user