diff --git a/framework/core/migrations/2017_04_07_114138_add_is_private_to_discussions.php b/framework/core/migrations/2017_04_07_114138_add_is_private_to_discussions.php new file mode 100644 index 000000000..c05a42baf --- /dev/null +++ b/framework/core/migrations/2017_04_07_114138_add_is_private_to_discussions.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Flarum\Database\Migration; + +return Migration::addColumns('discussions', [ + 'is_private' => ['boolean', 'default' => false] +]); diff --git a/framework/core/migrations/2017_04_07_114138_add_is_private_to_posts.php b/framework/core/migrations/2017_04_07_114138_add_is_private_to_posts.php new file mode 100644 index 000000000..14776dd47 --- /dev/null +++ b/framework/core/migrations/2017_04_07_114138_add_is_private_to_posts.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Flarum\Database\Migration; + +return Migration::addColumns('posts', [ + 'is_private' => ['boolean', 'default' => false] +]); diff --git a/framework/core/src/Core/Access/DiscussionPolicy.php b/framework/core/src/Core/Access/DiscussionPolicy.php index e9c242a1f..3abefa824 100644 --- a/framework/core/src/Core/Access/DiscussionPolicy.php +++ b/framework/core/src/Core/Access/DiscussionPolicy.php @@ -15,6 +15,7 @@ use Carbon\Carbon; use Flarum\Core\Discussion; use Flarum\Core\User; use Flarum\Event\ScopeHiddenDiscussionVisibility; +use Flarum\Event\ScopePrivateDiscussionVisibility; use Flarum\Settings\SettingsRepositoryInterface; use Illuminate\Contracts\Events\Dispatcher; use Illuminate\Database\Eloquent\Builder; @@ -44,6 +45,7 @@ class DiscussionPolicy extends AbstractPolicy /** * @param SettingsRepositoryInterface $settings * @param Gate $gate + * @param Dispatcher $events */ public function __construct(SettingsRepositoryInterface $settings, Gate $gate, Dispatcher $events) { @@ -70,6 +72,15 @@ class DiscussionPolicy extends AbstractPolicy */ public function find(User $actor, Builder $query) { + // Hide private discussions per default. + $query->where(function ($query) use ($actor) { + $query->where('discussions.is_private', false); + + $this->events->fire( + new ScopePrivateDiscussionVisibility($query, $actor) + ); + }); + if ($actor->cannot('viewDiscussions')) { $query->whereRaw('FALSE'); } elseif (! $actor->hasPermission('discussion.hide')) { diff --git a/framework/core/src/Core/Access/PostPolicy.php b/framework/core/src/Core/Access/PostPolicy.php index a968a44d8..afc0addb5 100644 --- a/framework/core/src/Core/Access/PostPolicy.php +++ b/framework/core/src/Core/Access/PostPolicy.php @@ -15,6 +15,7 @@ use Carbon\Carbon; use Flarum\Core\Post; use Flarum\Core\User; use Flarum\Event\ScopePostVisibility; +use Flarum\Event\ScopePrivatePostVisibility; use Flarum\Settings\SettingsRepositoryInterface; use Illuminate\Contracts\Events\Dispatcher; @@ -29,13 +30,18 @@ class PostPolicy extends AbstractPolicy * @var SettingsRepositoryInterface */ protected $settings; + /** + * @var Dispatcher + */ + protected $events; /** * @param SettingsRepositoryInterface $settings */ - public function __construct(SettingsRepositoryInterface $settings) + public function __construct(SettingsRepositoryInterface $settings, Dispatcher $events) { $this->settings = $settings; + $this->events = $events; } /** @@ -66,6 +72,15 @@ class PostPolicy extends AbstractPolicy */ public function scopePostVisibility(ScopePostVisibility $event) { + // Hide private posts per default. + $event->query->where(function ($query) use ($event) { + $query->where('posts.is_private', false); + + $this->events->fire( + new ScopePrivatePostVisibility($event->discussion, $query, $event->actor) + ); + }); + // When fetching a discussion's posts: if the user doesn't have permission // to moderate the discussion, then they can't see posts that have been // hidden by someone other than themself. diff --git a/framework/core/src/Core/Discussion.php b/framework/core/src/Core/Discussion.php index aadf92871..a73e437e2 100644 --- a/framework/core/src/Core/Discussion.php +++ b/framework/core/src/Core/Discussion.php @@ -49,6 +49,7 @@ use Flarum\Util\Str; * @property Post|null $lastPost * @property User|null $lastUser * @property \Illuminate\Database\Eloquent\Collection $readers + * @property bool $is_private */ class Discussion extends AbstractModel { @@ -72,6 +73,15 @@ class Discussion extends AbstractModel */ protected $dates = ['start_time', 'last_time', 'hide_time']; + /** + * Casts properties to a specific type. + * + * @var array + */ + protected $casts = [ + 'is_private' => 'boolean' + ]; + /** * The user for which the state relationship should be loaded. * diff --git a/framework/core/src/Core/Post.php b/framework/core/src/Core/Post.php index c6d952824..cb6717f4d 100755 --- a/framework/core/src/Core/Post.php +++ b/framework/core/src/Core/Post.php @@ -35,6 +35,7 @@ use Illuminate\Database\Eloquent\Builder; * @property User|null $editUser * @property User|null $hideUser * @property string $ip_address + * @property bool $is_private */ class Post extends AbstractModel { @@ -51,6 +52,15 @@ class Post extends AbstractModel */ protected $dates = ['time', 'edit_time', 'hide_time']; + /** + * Casts properties to a specific type. + * + * @var array + */ + protected $casts = [ + 'is_private' => 'boolean' + ]; + /** * A map of post types, as specified in the `type` column, to their * classes. diff --git a/framework/core/src/Event/ScopePrivateDiscussionVisibility.php b/framework/core/src/Event/ScopePrivateDiscussionVisibility.php new file mode 100644 index 000000000..2e6782b9f --- /dev/null +++ b/framework/core/src/Event/ScopePrivateDiscussionVisibility.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Flarum\Event; + +use Flarum\Core\User; +use Illuminate\Database\Eloquent\Builder; + +/** + * The `ScopePrivateDiscussionVisibility` event. + */ +class ScopePrivateDiscussionVisibility +{ + /** + * @var Builder + */ + public $query; + + /** + * @var User + */ + public $actor; + + /** + * @param Builder $query + * @param User $actor + */ + public function __construct(Builder $query, User $actor) + { + $this->query = $query; + $this->actor = $actor; + } +} diff --git a/framework/core/src/Event/ScopePrivatePostVisibility.php b/framework/core/src/Event/ScopePrivatePostVisibility.php new file mode 100644 index 000000000..bd67deb06 --- /dev/null +++ b/framework/core/src/Event/ScopePrivatePostVisibility.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Flarum\Event; + +use Flarum\Core\Discussion; +use Flarum\Core\User; +use Illuminate\Database\Eloquent\Builder; + +/** + * The `ScopePrivatePostVisibility` event. + */ +class ScopePrivatePostVisibility +{ + /** + * @var Discussion + */ + public $discussion; + + /** + * @var Builder + */ + public $query; + + /** + * @var User + */ + public $actor; + + /** + * @param Discussion $discussion + * @param Builder $query + * @param User $actor + */ + public function __construct(Discussion $discussion, Builder $query, User $actor) + { + $this->discussion = $discussion; + $this->query = $query; + $this->actor = $actor; + } +}