diff --git a/extensions/approval/bootstrap.php b/extensions/approval/bootstrap.php index 8b071843c..6ecf6a522 100644 --- a/extensions/approval/bootstrap.php +++ b/extensions/approval/bootstrap.php @@ -17,8 +17,9 @@ return function (Dispatcher $events) { $events->subscribe(Listener\AddClientAssets::class); $events->subscribe(Listener\AddPostApprovalAttributes::class); $events->subscribe(Listener\ApproveContent::class); - $events->subscribe(Listener\HideUnapprovedContent::class); $events->subscribe(Listener\UnapproveNewContent::class); $events->subscribe(Access\TagPolicy::class); + $events->subscribe(Access\DiscussionPolicy::class); + $events->subscribe(Access\PostPolicy::class); }; diff --git a/extensions/approval/composer.json b/extensions/approval/composer.json index ae8410422..c820e4924 100644 --- a/extensions/approval/composer.json +++ b/extensions/approval/composer.json @@ -15,7 +15,7 @@ "source": "https://github.com/flarum/flarum-ext-approval" }, "require": { - "flarum/core": "^0.1.0-beta.7", + "flarum/core": "^0.1.0-beta.8", "flarum/flarum-ext-flags": "^0.1.0-beta.6" }, "autoload": { diff --git a/extensions/approval/src/Access/DiscussionPolicy.php b/extensions/approval/src/Access/DiscussionPolicy.php new file mode 100644 index 000000000..45928e205 --- /dev/null +++ b/extensions/approval/src/Access/DiscussionPolicy.php @@ -0,0 +1,83 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Flarum\Approval\Access; + +use Flarum\Discussion\Discussion; +use Flarum\Event\ScopeModelVisibility; +use Flarum\User\AbstractPolicy; +use Flarum\User\User; +use Illuminate\Contracts\Events\Dispatcher; +use Illuminate\Database\Eloquent\Builder; + +class DiscussionPolicy extends AbstractPolicy +{ + /** + * {@inheritdoc} + */ + protected $model = Discussion::class; + + /** + * @var Dispatcher + */ + protected $events; + + /** + * @param Dispatcher $events + */ + public function __construct(Dispatcher $events) + { + $this->events = $events; + } + + /** + * @param Builder $query + * @param User $actor + */ + public function findEmpty(User $actor, Builder $query) + { + $this->showIfApprovable($actor, $query); + + } + + /** + * @param Builder $query + * @param User $actor + */ + public function findPrivate(User $actor, Builder $query) + { + $this->showIfApprovable($actor, $query); + } + + private function showIfApprovable(User $actor, Builder $query) + { + // Show empty/private discussions if they require approval and they are + // authored by the current user, or the current user has permission to + // approve posts. + $query->where('discussions.is_approved', 0); + + if (! $actor->hasPermission('discussion.approvePosts')) { + $query->where(function (Builder $query) use ($actor) { + $query->where('start_user_id', $actor->id) + ->orWhere($this->canApprovePosts($actor)); + }); + } + } + + private function canApprovePosts(User $actor) + { + return function ($query) use ($actor) { + $this->events->dispatch( + new ScopeModelVisibility($query, $actor, 'approvePosts') + ); + }; + } +} diff --git a/extensions/approval/src/Access/PostPolicy.php b/extensions/approval/src/Access/PostPolicy.php new file mode 100644 index 000000000..4f869f54e --- /dev/null +++ b/extensions/approval/src/Access/PostPolicy.php @@ -0,0 +1,77 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Flarum\Approval\Access; + +use Flarum\Event\ScopeModelVisibility; +use Flarum\Post\Post; +use Flarum\User\AbstractPolicy; +use Flarum\User\User; +use Illuminate\Contracts\Events\Dispatcher; +use Illuminate\Database\Eloquent\Builder; + +class PostPolicy extends AbstractPolicy +{ + /** + * {@inheritdoc} + */ + protected $model = Post::class; + + /** + * @var Dispatcher + */ + protected $events; + + /** + * @param Dispatcher $events + */ + public function __construct(Dispatcher $events) + { + $this->events = $events; + } + + /** + * @param Builder $query + * @param User $actor + */ + public function findPrivate(User $actor, Builder $query) + { + // Show private posts if they require approval and they are + // authored by the current user, or the current user has permission to + // approve posts. + $query->where('posts.is_approved', 0); + + if (! $actor->hasPermission('discussion.approvePosts')) { + $query->where(function (Builder $query) use ($actor) { + $query->where('start_user_id', $actor->id) + ->orWhereExists($this->discussionWhereCanApprovePosts($actor)); + }); + } + } + + private function discussionWhereCanApprovePosts(User $actor) + { + return function ($query) use ($actor) { + $query->selectRaw('1') + ->from('discussions') + ->whereRaw('discussions.id = posts.discussion_id') + ->where($this->canApprovePosts($actor)); + }; + } + + private function canApprovePosts(User $actor) + { + return function ($query) use ($actor) { + $this->events->dispatch( + new ScopeModelVisibility($query, $actor, 'approvePosts') + ); + }; + } +} diff --git a/extensions/approval/src/Listener/HideUnapprovedContent.php b/extensions/approval/src/Listener/HideUnapprovedContent.php deleted file mode 100644 index 2a3491636..000000000 --- a/extensions/approval/src/Listener/HideUnapprovedContent.php +++ /dev/null @@ -1,79 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Flarum\Approval\Listener; - -use Flarum\Discussion\Discussion; -use Flarum\Event\ScopeHiddenDiscussionVisibility; -use Flarum\Event\ScopeModelVisibility; -use Flarum\Event\ScopePostVisibility; -use Illuminate\Contracts\Events\Dispatcher; - -class HideUnapprovedContent -{ - /** - * @var Dispatcher - */ - protected $events; - - /** - * @param Dispatcher $events - */ - public function __construct(Dispatcher $events) - { - $this->events = $events; - } - - /** - * @param Dispatcher $events - */ - public function subscribe(Dispatcher $events) - { - $events->listen(ScopeModelVisibility::class, [$this, 'hideUnapprovedDiscussions']); - $events->listen(ScopePostVisibility::class, [$this, 'hideUnapprovedPosts']); - } - - /** - * @param ScopeModelVisibility $event - */ - public function hideUnapprovedDiscussions(ScopeModelVisibility $event) - { - if ($event->model instanceof Discussion) { - $user = $event->actor; - - if (! $user->hasPermission('discussion.editPosts')) { - $event->query->where(function ($query) use ($user) { - $query->where('discussions.is_approved', 1) - ->orWhere('start_user_id', $user->id); - - $this->events->fire( - new ScopeHiddenDiscussionVisibility($query, $user, 'discussion.editPosts') - ); - }); - } - } - } - - /** - * @param ScopePostVisibility $event - */ - public function hideUnapprovedPosts(ScopePostVisibility $event) - { - if ($event->actor->can('editPosts', $event->discussion)) { - return; - } - - $event->query->where(function ($query) use ($event) { - $query->where('posts.is_approved', 1) - ->orWhere('user_id', $event->actor->id); - }); - } -} diff --git a/extensions/approval/src/Listener/UnapproveNewContent.php b/extensions/approval/src/Listener/UnapproveNewContent.php index b3a02b238..990bcf593 100644 --- a/extensions/approval/src/Listener/UnapproveNewContent.php +++ b/extensions/approval/src/Listener/UnapproveNewContent.php @@ -11,7 +11,9 @@ namespace Flarum\Approval\Listener; +use Flarum\Discussion\Discussion; use Flarum\Event\ConfigureModelDefaultAttributes; +use Flarum\Event\GetModelIsPrivate; use Flarum\Flags\Flag; use Flarum\Post\Event\Saving; use Flarum\Post\Post; @@ -26,6 +28,7 @@ class UnapproveNewContent { $events->listen(ConfigureModelDefaultAttributes::class, [$this, 'approveByDefault']); $events->listen(Saving::class, [$this, 'unapproveNewPosts']); + $events->listen(GetModelIsPrivate::class, [$this, 'markUnapprovedContentAsPrivate']); } /** @@ -74,4 +77,17 @@ class UnapproveNewContent }); } } + + /** + * @param GetModelIsPrivate $event + * @return bool|null + */ + public function markUnapprovedContentAsPrivate(GetModelIsPrivate $event) + { + if ($event->model instanceof Post || $event->model instanceof Discussion) { + if (! $event->model->is_approved) { + return true; + } + } + } }