mirror of
https://github.com/flarum/framework.git
synced 2024-11-22 12:44:31 +08:00
Deprecate GetModelIsPrivate, replace with extender (#2587)
This commit is contained in:
parent
17f15e36eb
commit
8366ec720e
|
@ -9,7 +9,10 @@
|
|||
|
||||
namespace Flarum\Database;
|
||||
|
||||
use Flarum\Discussion\Discussion;
|
||||
use Flarum\Event\GetModelIsPrivate;
|
||||
use Flarum\Foundation\AbstractServiceProvider;
|
||||
use Flarum\Post\Post;
|
||||
use Illuminate\Database\Capsule\Manager;
|
||||
use Illuminate\Database\ConnectionInterface;
|
||||
use Illuminate\Database\ConnectionResolverInterface;
|
||||
|
@ -58,6 +61,15 @@ class DatabaseServiceProvider extends AbstractServiceProvider
|
|||
$this->app->singleton(MigrationRepositoryInterface::class, function ($app) {
|
||||
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::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\Restored;
|
||||
use Flarum\Discussion\Event\Started;
|
||||
use Flarum\Event\GetModelIsPrivate;
|
||||
use Flarum\Foundation\EventGeneratorTrait;
|
||||
use Flarum\Notification\Notification;
|
||||
use Flarum\Post\MergeableInterface;
|
||||
|
@ -109,12 +108,6 @@ class Discussion extends AbstractModel
|
|||
|
||||
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;
|
||||
|
||||
/**
|
||||
* @deprecated beta 16, remove beta 17.
|
||||
*
|
||||
* Determine whether or not a model should be marked as `is_private`.
|
||||
*/
|
||||
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\ScopeVisibilityTrait;
|
||||
use Flarum\Discussion\Discussion;
|
||||
use Flarum\Event\GetModelIsPrivate;
|
||||
use Flarum\Foundation\EventGeneratorTrait;
|
||||
use Flarum\Notification\Notification;
|
||||
use Flarum\Post\Event\Deleted;
|
||||
|
@ -96,12 +95,6 @@ class Post extends AbstractModel
|
|||
$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) {
|
||||
$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';
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user