1
0
mirror of https://github.com/flarum/core.git synced 2025-07-20 00:01:17 +02:00

User Extender (prepareGroups functionality) (#2110)

This commit is contained in:
Alexander Skvortsov
2020-07-17 06:18:35 -04:00
committed by GitHub
parent b89ccaf83c
commit c10ebea00c
5 changed files with 93 additions and 2 deletions

View File

@@ -12,6 +12,7 @@ namespace Flarum\Event;
use Flarum\User\User; use Flarum\User\User;
/** /**
* @deprecated beta 13, remove in beta 14. Use the User extender instead.
* The `PrepareUserGroups` event. * The `PrepareUserGroups` event.
*/ */
class PrepareUserGroups class PrepareUserGroups

View File

@@ -15,9 +15,10 @@ use Illuminate\Contracts\Container\Container;
class User implements ExtenderInterface class User implements ExtenderInterface
{ {
private $displayNameDrivers = []; private $displayNameDrivers = [];
private $groupProcessors = [];
/** /**
* Add a mail driver. * Add a display name driver.
* *
* @param string $identifier Identifier for display name driver. E.g. 'username' for UserNameDriver * @param string $identifier Identifier for display name driver. E.g. 'username' for UserNameDriver
* @param string $driver ::class attribute of driver class, which must implement Flarum\User\DisplayName\DriverInterface * @param string $driver ::class attribute of driver class, which must implement Flarum\User\DisplayName\DriverInterface
@@ -29,10 +30,35 @@ class User implements ExtenderInterface
return $this; return $this;
} }
/**
* Dynamically process a user's list of groups when calculating permissions.
* This can be used to give a user permissions for groups they aren't actually in, based on context.
* It will not change the group badges displayed for the user.
*
* @param callable $callable
*
* The callable can be a closure or invokable class, and should accept:
* - \Flarum\User\User $user: the user in question.
* - array $groupIds: an array of ids for the groups the user belongs to.
*
* The callable should return:
* - array $groupIds: an array of ids for the groups the user belongs to.
*/
public function permissionGroups(callable $callable)
{
$this->groupProcessors[] = $callable;
return $this;
}
public function extend(Container $container, Extension $extension = null) public function extend(Container $container, Extension $extension = null)
{ {
$container->extend('flarum.user.display_name.supported_drivers', function ($existingDrivers) { $container->extend('flarum.user.display_name.supported_drivers', function ($existingDrivers) {
return array_merge($existingDrivers, $this->displayNameDrivers); return array_merge($existingDrivers, $this->displayNameDrivers);
}); });
$container->extend('flarum.user.group_processors', function ($existingRelations) {
return array_merge($existingRelations, $this->groupProcessors);
});
} }
} }

View File

@@ -83,6 +83,12 @@ class User extends AbstractModel
*/ */
protected $session; protected $session;
/**
* An array of callables, through each of which the user's list of groups is passed
* before being returned.
*/
protected static $groupProcessors = [];
/** /**
* An array of registered user preferences. Each preference is defined with * An array of registered user preferences. Each preference is defined with
* a key, and its value is an array containing the following keys:. * a key, and its value is an array containing the following keys:.
@@ -660,8 +666,13 @@ class User extends AbstractModel
$groupIds = array_merge($groupIds, [Group::MEMBER_ID], $this->groups->pluck('id')->all()); $groupIds = array_merge($groupIds, [Group::MEMBER_ID], $this->groups->pluck('id')->all());
} }
// Deprecated, remove in beta 14.
event(new PrepareUserGroups($this, $groupIds)); event(new PrepareUserGroups($this, $groupIds));
foreach (static::$groupProcessors as $processor) {
$groupIds = $processor($this, $groupIds);
}
return Permission::whereIn('group_id', $groupIds); return Permission::whereIn('group_id', $groupIds);
} }
@@ -751,6 +762,17 @@ class User extends AbstractModel
static::$preferences[$key] = compact('transformer', 'default'); static::$preferences[$key] = compact('transformer', 'default');
} }
/**
* Register a callback that processes a user's list of groups.
*
* @param callable $callback
* @return array $groupIds
*/
public static function addGroupProcessor($callback)
{
static::$groupProcessors[] = $callback;
}
/** /**
* Get the key for a preference which flags whether or not the user will * Get the key for a preference which flags whether or not the user will
* receive a notification for $type via $method. * receive a notification for $type via $method.

View File

@@ -31,6 +31,10 @@ class UserServiceProvider extends AbstractServiceProvider
{ {
$this->registerAvatarsFilesystem(); $this->registerAvatarsFilesystem();
$this->registerDisplayNameDrivers(); $this->registerDisplayNameDrivers();
$this->app->singleton('flarum.user.group_processors', function () {
return [];
});
} }
protected function registerDisplayNameDrivers() protected function registerDisplayNameDrivers()
@@ -72,6 +76,14 @@ class UserServiceProvider extends AbstractServiceProvider
*/ */
public function boot() public function boot()
{ {
foreach ($this->app->make('flarum.user.group_processors') as $callback) {
if (is_string($callback)) {
$callback = $this->app->make($callback);
}
User::addGroupProcessor($callback);
}
User::setHasher($this->app->make('hash')); User::setHasher($this->app->make('hash'));
User::setGate($this->app->make(Gate::class)); User::setGate($this->app->make(Gate::class));
User::setDisplayNameDriver($this->app->make('flarum.user.display_name.driver')); User::setDisplayNameDriver($this->app->make('flarum.user.display_name.driver'));

View File

@@ -24,7 +24,9 @@ class UserTest extends TestCase
$this->prepareDatabase([ $this->prepareDatabase([
'users' => [ 'users' => [
$this->adminUser(), $this->adminUser(),
], 'settings' => [ $this->normalUser(),
],
'settings' => [
['key' => 'display_name_driver', 'value' => 'custom'], ['key' => 'display_name_driver', 'value' => 'custom'],
], ],
]); ]);
@@ -58,6 +60,34 @@ class UserTest extends TestCase
$this->assertEquals('admin@machine.local$$$suffix', $user->displayName); $this->assertEquals('admin@machine.local$$$suffix', $user->displayName);
} }
/**
* @test
*/
public function user_has_permissions_for_expected_groups_if_no_processors_added()
{
$this->prepDb();
$user = User::find(2);
$this->assertContains('viewUserList', $user->getPermissions());
}
/**
* @test
*/
public function processor_can_restrict_user_groups()
{
$this->extend((new Extend\User)->permissionGroups(function (User $user, array $groupIds) {
return array_filter($groupIds, function ($id) {
return $id != 3;
});
}));
$this->prepDb();
$user = User::find(2);
$this->assertNotContains('viewUserList', $user->getPermissions());
}
} }
class CustomDisplayNameDriver implements DriverInterface class CustomDisplayNameDriver implements DriverInterface