mirror of
https://github.com/flarum/core.git
synced 2025-07-15 13:56:23 +02:00
Deprecate GetModelIsPrivate, replace with extender (#2587)
This commit is contained in:
committed by
GitHub
parent
17f15e36eb
commit
8366ec720e
@ -9,7 +9,10 @@
|
|||||||
|
|
||||||
namespace Flarum\Database;
|
namespace Flarum\Database;
|
||||||
|
|
||||||
|
use Flarum\Discussion\Discussion;
|
||||||
|
use Flarum\Event\GetModelIsPrivate;
|
||||||
use Flarum\Foundation\AbstractServiceProvider;
|
use Flarum\Foundation\AbstractServiceProvider;
|
||||||
|
use Flarum\Post\Post;
|
||||||
use Illuminate\Database\Capsule\Manager;
|
use Illuminate\Database\Capsule\Manager;
|
||||||
use Illuminate\Database\ConnectionInterface;
|
use Illuminate\Database\ConnectionInterface;
|
||||||
use Illuminate\Database\ConnectionResolverInterface;
|
use Illuminate\Database\ConnectionResolverInterface;
|
||||||
@ -58,6 +61,15 @@ class DatabaseServiceProvider extends AbstractServiceProvider
|
|||||||
$this->app->singleton(MigrationRepositoryInterface::class, function ($app) {
|
$this->app->singleton(MigrationRepositoryInterface::class, function ($app) {
|
||||||
return new DatabaseMigrationRepository($app['flarum.db'], 'migrations');
|
return new DatabaseMigrationRepository($app['flarum.db'], 'migrations');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$this->app->singleton('flarum.database.model_private_checkers', function () {
|
||||||
|
// Discussion and Post are explicitly listed here to trigger the deprecated
|
||||||
|
// event-based model privacy system. They should be removed in beta 17.
|
||||||
|
return [
|
||||||
|
Discussion::class => [],
|
||||||
|
Post::class => []
|
||||||
|
];
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -67,5 +79,24 @@ class DatabaseServiceProvider extends AbstractServiceProvider
|
|||||||
{
|
{
|
||||||
AbstractModel::setConnectionResolver($this->app->make(ConnectionResolverInterface::class));
|
AbstractModel::setConnectionResolver($this->app->make(ConnectionResolverInterface::class));
|
||||||
AbstractModel::setEventDispatcher($this->app->make('events'));
|
AbstractModel::setEventDispatcher($this->app->make('events'));
|
||||||
|
|
||||||
|
foreach ($this->app->make('flarum.database.model_private_checkers') as $modelClass => $checkers) {
|
||||||
|
$modelClass::saving(function ($instance) use ($checkers) {
|
||||||
|
foreach ($checkers as $checker) {
|
||||||
|
if ($checker($instance) === true) {
|
||||||
|
$instance->is_private = true;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$instance->is_private = false;
|
||||||
|
|
||||||
|
// @deprecated BC layer, remove beta 17
|
||||||
|
$event = new GetModelIsPrivate($instance);
|
||||||
|
|
||||||
|
$instance->is_private = $this->app->make('events')->until($event) === true;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,6 @@ use Flarum\Discussion\Event\Hidden;
|
|||||||
use Flarum\Discussion\Event\Renamed;
|
use Flarum\Discussion\Event\Renamed;
|
||||||
use Flarum\Discussion\Event\Restored;
|
use Flarum\Discussion\Event\Restored;
|
||||||
use Flarum\Discussion\Event\Started;
|
use Flarum\Discussion\Event\Started;
|
||||||
use Flarum\Event\GetModelIsPrivate;
|
|
||||||
use Flarum\Foundation\EventGeneratorTrait;
|
use Flarum\Foundation\EventGeneratorTrait;
|
||||||
use Flarum\Notification\Notification;
|
use Flarum\Notification\Notification;
|
||||||
use Flarum\Post\MergeableInterface;
|
use Flarum\Post\MergeableInterface;
|
||||||
@ -109,12 +108,6 @@ class Discussion extends AbstractModel
|
|||||||
|
|
||||||
Notification::whereSubject($discussion)->delete();
|
Notification::whereSubject($discussion)->delete();
|
||||||
});
|
});
|
||||||
|
|
||||||
static::saving(function (self $discussion) {
|
|
||||||
$event = new GetModelIsPrivate($discussion);
|
|
||||||
|
|
||||||
$discussion->is_private = static::$dispatcher->until($event) === true;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -12,6 +12,8 @@ namespace Flarum\Event;
|
|||||||
use Flarum\Database\AbstractModel;
|
use Flarum\Database\AbstractModel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @deprecated beta 16, remove beta 17.
|
||||||
|
*
|
||||||
* Determine whether or not a model should be marked as `is_private`.
|
* Determine whether or not a model should be marked as `is_private`.
|
||||||
*/
|
*/
|
||||||
class GetModelIsPrivate
|
class GetModelIsPrivate
|
||||||
|
82
src/Extend/ModelPrivate.php
Normal file
82
src/Extend/ModelPrivate.php
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
<?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\Extend;
|
||||||
|
|
||||||
|
use Flarum\Extension\Extension;
|
||||||
|
use Flarum\Foundation\ContainerUtil;
|
||||||
|
use Illuminate\Contracts\Container\Container;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Some models, in particular Discussion and Post, are intended to
|
||||||
|
* support a "private" mode, wherein they aren't visible unless some
|
||||||
|
* criteria is met. This can be used to implement anything from
|
||||||
|
* private discussions to post approvals.
|
||||||
|
*
|
||||||
|
* When a model is saved, any "privacy checkers" registered for it will
|
||||||
|
* be run. If any privacy checkers return `true`, the `is_private` field
|
||||||
|
* of that model instance will be set to `true`. Otherwise, it will be set to
|
||||||
|
* `false`. Accordingly, this is only available for models with an `is_private`
|
||||||
|
* field.
|
||||||
|
*
|
||||||
|
* In Flarum core, the Discussion and Post models come with private support.
|
||||||
|
* Core also contains visibility scopers that hide instances of these models
|
||||||
|
* with `is_private = true` from queries. Extensions can register custom scopers
|
||||||
|
* for these classes with the `viewPrivate` ability to grant access to view some
|
||||||
|
* private instances under some conditions.
|
||||||
|
*/
|
||||||
|
class ModelPrivate implements ExtenderInterface
|
||||||
|
{
|
||||||
|
private $modelClass;
|
||||||
|
private $checkers = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $modelClass The ::class attribute of the model you are applying scopers to.
|
||||||
|
* This model must have a `is_private` field.
|
||||||
|
*/
|
||||||
|
public function __construct(string $modelClass)
|
||||||
|
{
|
||||||
|
$this->modelClass = $modelClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a model privacy checker.
|
||||||
|
*
|
||||||
|
* @param callable|string $callback
|
||||||
|
*
|
||||||
|
* The callback can be a closure or invokable class, and should accept:
|
||||||
|
* - \Flarum\User\User $actor
|
||||||
|
* - \Illuminate\Database\Eloquent\Builder $query
|
||||||
|
*
|
||||||
|
* It should return `true` if the model instance should be made private.
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function checker($callback)
|
||||||
|
{
|
||||||
|
$this->checkers[] = $callback;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function extend(Container $container, Extension $extension = null)
|
||||||
|
{
|
||||||
|
if (! class_exists($this->modelClass)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$container->extend('flarum.database.model_private_checkers', function ($originalCheckers) use ($container) {
|
||||||
|
foreach ($this->checkers as $checker) {
|
||||||
|
$originalCheckers[$this->modelClass][] = ContainerUtil::wrapCallback($checker, $container);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $originalCheckers;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -12,7 +12,6 @@ namespace Flarum\Post;
|
|||||||
use Flarum\Database\AbstractModel;
|
use Flarum\Database\AbstractModel;
|
||||||
use Flarum\Database\ScopeVisibilityTrait;
|
use Flarum\Database\ScopeVisibilityTrait;
|
||||||
use Flarum\Discussion\Discussion;
|
use Flarum\Discussion\Discussion;
|
||||||
use Flarum\Event\GetModelIsPrivate;
|
|
||||||
use Flarum\Foundation\EventGeneratorTrait;
|
use Flarum\Foundation\EventGeneratorTrait;
|
||||||
use Flarum\Notification\Notification;
|
use Flarum\Notification\Notification;
|
||||||
use Flarum\Post\Event\Deleted;
|
use Flarum\Post\Event\Deleted;
|
||||||
@ -96,12 +95,6 @@ class Post extends AbstractModel
|
|||||||
$post->discussion->save();
|
$post->discussion->save();
|
||||||
});
|
});
|
||||||
|
|
||||||
static::saving(function (self $post) {
|
|
||||||
$event = new GetModelIsPrivate($post);
|
|
||||||
|
|
||||||
$post->is_private = static::$dispatcher->until($event) === true;
|
|
||||||
});
|
|
||||||
|
|
||||||
static::deleted(function (self $post) {
|
static::deleted(function (self $post) {
|
||||||
$post->raise(new Deleted($post));
|
$post->raise(new Deleted($post));
|
||||||
|
|
||||||
|
121
tests/integration/extenders/ModelPrivateTest.php
Normal file
121
tests/integration/extenders/ModelPrivateTest.php
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
<?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\Tests\integration\extenders;
|
||||||
|
|
||||||
|
use Flarum\Discussion\Discussion;
|
||||||
|
use Flarum\Extend;
|
||||||
|
use Flarum\Tests\integration\RetrievesAuthorizedUsers;
|
||||||
|
use Flarum\Tests\integration\TestCase;
|
||||||
|
use Flarum\User\User;
|
||||||
|
|
||||||
|
class ModelPrivateTest extends TestCase
|
||||||
|
{
|
||||||
|
use RetrievesAuthorizedUsers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function discussion_isnt_saved_as_private_by_default()
|
||||||
|
{
|
||||||
|
$this->app();
|
||||||
|
|
||||||
|
$user = User::find(1);
|
||||||
|
|
||||||
|
$discussion = Discussion::start('Some Discussion', $user);
|
||||||
|
$discussion->save();
|
||||||
|
|
||||||
|
$this->assertFalse($discussion->is_private);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function discussion_is_saved_as_private_if_privacy_checker_added()
|
||||||
|
{
|
||||||
|
$this->extend(
|
||||||
|
(new Extend\ModelPrivate(Discussion::class))
|
||||||
|
->checker(function ($discussion) {
|
||||||
|
return $discussion->title === 'Private Discussion';
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->app();
|
||||||
|
|
||||||
|
$user = User::find(1);
|
||||||
|
|
||||||
|
$privateDiscussion = Discussion::start('Private Discussion', $user);
|
||||||
|
$publicDiscussion = Discussion::start('Public Discussion', $user);
|
||||||
|
$privateDiscussion->save();
|
||||||
|
$publicDiscussion->save();
|
||||||
|
|
||||||
|
$this->assertTrue($privateDiscussion->is_private);
|
||||||
|
$this->assertFalse($publicDiscussion->is_private);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function discussion_is_saved_as_private_if_privacy_checker_added_via_invokable_class()
|
||||||
|
{
|
||||||
|
$this->extend(
|
||||||
|
(new Extend\ModelPrivate(Discussion::class))
|
||||||
|
->checker(CustomPrivateChecker::class)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->app();
|
||||||
|
|
||||||
|
$user = User::find(1);
|
||||||
|
|
||||||
|
$privateDiscussion = Discussion::start('Private Discussion', $user);
|
||||||
|
$publicDiscussion = Discussion::start('Public Discussion', $user);
|
||||||
|
$privateDiscussion->save();
|
||||||
|
$publicDiscussion->save();
|
||||||
|
|
||||||
|
$this->assertTrue($privateDiscussion->is_private);
|
||||||
|
$this->assertFalse($publicDiscussion->is_private);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function private_checkers_that_return_false_dont_matter()
|
||||||
|
{
|
||||||
|
$this->extend(
|
||||||
|
(new Extend\ModelPrivate(Discussion::class))
|
||||||
|
->checker(function ($discussion) {
|
||||||
|
return false;
|
||||||
|
})
|
||||||
|
->checker(CustomPrivateChecker::class)
|
||||||
|
->checker(function ($discussion) {
|
||||||
|
return false;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->app();
|
||||||
|
|
||||||
|
$user = User::find(1);
|
||||||
|
|
||||||
|
$privateDiscussion = Discussion::start('Private Discussion', $user);
|
||||||
|
$publicDiscussion = Discussion::start('Public Discussion', $user);
|
||||||
|
$privateDiscussion->save();
|
||||||
|
$publicDiscussion->save();
|
||||||
|
|
||||||
|
$this->assertTrue($privateDiscussion->is_private);
|
||||||
|
$this->assertFalse($publicDiscussion->is_private);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CustomPrivateChecker
|
||||||
|
{
|
||||||
|
public function __invoke($discussion)
|
||||||
|
{
|
||||||
|
return $discussion->title === 'Private Discussion';
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user