From f7985bac61d5f01a84220f4acb1baac6bd7ec897 Mon Sep 17 00:00:00 2001
From: Alexander Skvortsov <38059171+askvortsov1@users.noreply.github.com>
Date: Tue, 19 May 2020 18:45:56 -0400
Subject: [PATCH] Use drivers for display names, add display name extender
(#2174)
* Deprecate GetDisplayName event
* Add interface for display name driver
* Add username driver as default
* Add code to register supported drivers / used driver as singletons
* Configured User class to use new driver-based system for display names
* Add extender for adding display name driver
* Add integration test for user display name driver
* Add frontend UI for selecting display name driver
---
.../js/src/admin/components/BasicsPage.js | 23 +++++++
.../core/src/Admin/Content/AdminPayload.php | 19 ++++-
framework/core/src/Extend/User.php | 38 ++++++++++
.../src/User/DisplayName/DriverInterface.php | 25 +++++++
.../src/User/DisplayName/UsernameDriver.php | 23 +++++++
.../core/src/User/Event/GetDisplayName.php | 3 +
framework/core/src/User/User.php | 21 +++++-
.../core/src/User/UserServiceProvider.php | 29 ++++++++
.../tests/integration/extenders/UserTest.php | 69 +++++++++++++++++++
9 files changed, 247 insertions(+), 3 deletions(-)
create mode 100644 framework/core/src/Extend/User.php
create mode 100644 framework/core/src/User/DisplayName/DriverInterface.php
create mode 100644 framework/core/src/User/DisplayName/UsernameDriver.php
create mode 100644 framework/core/tests/integration/extenders/UserTest.php
diff --git a/framework/core/js/src/admin/components/BasicsPage.js b/framework/core/js/src/admin/components/BasicsPage.js
index 746bcce8b..fb692c4fc 100644
--- a/framework/core/js/src/admin/components/BasicsPage.js
+++ b/framework/core/js/src/admin/components/BasicsPage.js
@@ -21,6 +21,7 @@ export default class BasicsPage extends Page {
'default_route',
'welcome_title',
'welcome_message',
+ 'display_name_driver',
];
this.values = {};
@@ -33,6 +34,14 @@ export default class BasicsPage extends Page {
this.localeOptions[i] = `${locales[i]} (${i})`;
}
+ this.displayNameOptions = {};
+ const displayNameDrivers = app.data.displayNameDrivers;
+ displayNameDrivers.forEach(function (identifier) {
+ this.displayNameOptions[identifier] = identifier;
+ }, this);
+
+ if (!this.values.display_name_driver() && displayNameDrivers.includes('username')) this.values.display_name_driver('username');
+
if (typeof this.values.show_language_selector() !== 'number') this.values.show_language_selector(1);
}
@@ -114,6 +123,20 @@ export default class BasicsPage extends Page {
],
})}
+ {Object.keys(this.displayNameOptions).length > 1
+ ? FieldSet.component({
+ label: app.translator.trans('core.admin.basics.display_name_heading'),
+ children: [
+
{app.translator.trans('core.admin.basics.display_name_text')}
,
+ Select.component({
+ options: this.displayNameOptions,
+ value: this.values.display_name_driver(),
+ onchange: this.values.display_name_driver,
+ }),
+ ],
+ })
+ : ''}
+
{Button.component({
type: 'submit',
className: 'Button Button--primary',
diff --git a/framework/core/src/Admin/Content/AdminPayload.php b/framework/core/src/Admin/Content/AdminPayload.php
index 685289107..e766c072a 100644
--- a/framework/core/src/Admin/Content/AdminPayload.php
+++ b/framework/core/src/Admin/Content/AdminPayload.php
@@ -14,12 +14,18 @@ use Flarum\Frontend\Document;
use Flarum\Group\Permission;
use Flarum\Settings\Event\Deserializing;
use Flarum\Settings\SettingsRepositoryInterface;
+use Illuminate\Contracts\Container\Container;
use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Database\ConnectionInterface;
use Psr\Http\Message\ServerRequestInterface as Request;
class AdminPayload
{
+ /**
+ * @var Container;
+ */
+ protected $container;
+
/**
* @var SettingsRepositoryInterface
*/
@@ -36,13 +42,20 @@ class AdminPayload
protected $db;
/**
+ * @param Container $container
* @param SettingsRepositoryInterface $settings
* @param ExtensionManager $extensions
* @param ConnectionInterface $db
* @param Dispatcher $events
*/
- public function __construct(SettingsRepositoryInterface $settings, ExtensionManager $extensions, ConnectionInterface $db, Dispatcher $events)
- {
+ public function __construct(
+ Container $container,
+ SettingsRepositoryInterface $settings,
+ ExtensionManager $extensions,
+ ConnectionInterface $db,
+ Dispatcher $events
+ ) {
+ $this->container = $container;
$this->settings = $settings;
$this->extensions = $extensions;
$this->db = $db;
@@ -61,6 +74,8 @@ class AdminPayload
$document->payload['permissions'] = Permission::map();
$document->payload['extensions'] = $this->extensions->getExtensions()->toArray();
+ $document->payload['displayNameDrivers'] = array_keys($this->container->make('flarum.user.display_name.supported_drivers'));
+
$document->payload['phpVersion'] = PHP_VERSION;
$document->payload['mysqlVersion'] = $this->db->selectOne('select version() as version')->version;
}
diff --git a/framework/core/src/Extend/User.php b/framework/core/src/Extend/User.php
new file mode 100644
index 000000000..6882757d0
--- /dev/null
+++ b/framework/core/src/Extend/User.php
@@ -0,0 +1,38 @@
+drivers[$identifier] = $driver;
+
+ return $this;
+ }
+
+ public function extend(Container $container, Extension $extension = null)
+ {
+ $container->extend('flarum.user.display_name.supported_drivers', function ($existingDrivers) {
+ return array_merge($existingDrivers, $this->drivers);
+ });
+ }
+}
diff --git a/framework/core/src/User/DisplayName/DriverInterface.php b/framework/core/src/User/DisplayName/DriverInterface.php
new file mode 100644
index 000000000..f04207532
--- /dev/null
+++ b/framework/core/src/User/DisplayName/DriverInterface.php
@@ -0,0 +1,25 @@
+username;
+ }
+}
diff --git a/framework/core/src/User/Event/GetDisplayName.php b/framework/core/src/User/Event/GetDisplayName.php
index ff35307c0..73106c70a 100644
--- a/framework/core/src/User/Event/GetDisplayName.php
+++ b/framework/core/src/User/Event/GetDisplayName.php
@@ -11,6 +11,9 @@ namespace Flarum\User\Event;
use Flarum\User\User;
+/**
+ * @deprecated beta 14, removed beta 15.
+ */
class GetDisplayName
{
/**
diff --git a/framework/core/src/User/User.php b/framework/core/src/User/User.php
index 8fc28e74c..a9d0eeb1b 100644
--- a/framework/core/src/User/User.php
+++ b/framework/core/src/User/User.php
@@ -23,6 +23,7 @@ use Flarum\Http\AccessToken;
use Flarum\Http\UrlGenerator;
use Flarum\Notification\Notification;
use Flarum\Post\Post;
+use Flarum\User\DisplayName\DriverInterface;
use Flarum\User\Event\Activated;
use Flarum\User\Event\AvatarChanged;
use Flarum\User\Event\CheckingPassword;
@@ -93,6 +94,13 @@ class User extends AbstractModel
*/
protected static $preferences = [];
+ /**
+ * A driver for getting display names.
+ *
+ * @var DriverInterface
+ */
+ protected static $displayNameDriver;
+
/**
* The hasher with which to hash passwords.
*
@@ -172,6 +180,16 @@ class User extends AbstractModel
static::$gate = $gate;
}
+ /**
+ * Set the display name driver.
+ *
+ * @param DriverInterface $driver
+ */
+ public static function setDisplayNameDriver(DriverInterface $driver)
+ {
+ static::$displayNameDriver = $driver;
+ }
+
/**
* Rename the user.
*
@@ -309,7 +327,8 @@ class User extends AbstractModel
*/
public function getDisplayNameAttribute()
{
- return static::$dispatcher->until(new GetDisplayName($this)) ?: $this->username;
+ // Event is deprecated in beta 14, remove in beta 15.
+ return static::$dispatcher->until(new GetDisplayName($this)) ?: static::$displayNameDriver->displayName($this);
}
/**
diff --git a/framework/core/src/User/UserServiceProvider.php b/framework/core/src/User/UserServiceProvider.php
index 88f5b93ec..881f15b79 100644
--- a/framework/core/src/User/UserServiceProvider.php
+++ b/framework/core/src/User/UserServiceProvider.php
@@ -12,12 +12,16 @@ namespace Flarum\User;
use Flarum\Event\ConfigureUserPreferences;
use Flarum\Event\GetPermission;
use Flarum\Foundation\AbstractServiceProvider;
+use Flarum\Settings\SettingsRepositoryInterface;
+use Flarum\User\DisplayName\DriverInterface;
+use Flarum\User\DisplayName\UsernameDriver;
use Flarum\User\Event\EmailChangeRequested;
use Flarum\User\Event\Registered;
use Flarum\User\Event\Saving;
use Illuminate\Contracts\Auth\Access\Gate as GateContract;
use Illuminate\Contracts\Container\Container;
use Illuminate\Contracts\Filesystem\Factory;
+use Illuminate\Support\Arr;
use League\Flysystem\FilesystemInterface;
use RuntimeException;
@@ -30,6 +34,30 @@ class UserServiceProvider extends AbstractServiceProvider
{
$this->registerGate();
$this->registerAvatarsFilesystem();
+ $this->registerDisplayNameDrivers();
+ }
+
+ protected function registerDisplayNameDrivers()
+ {
+ $this->app->singleton('flarum.user.display_name.supported_drivers', function () {
+ return [
+ 'username' => UsernameDriver::class,
+ ];
+ });
+
+ $this->app->singleton('flarum.user.display_name.driver', function () {
+ $drivers = $this->app->make('flarum.user.display_name.supported_drivers');
+ $settings = $this->app->make(SettingsRepositoryInterface::class);
+ $driverName = $settings->get('display_name_driver', '');
+
+ $driverClass = Arr::get($drivers, $driverName);
+
+ return $driverClass
+ ? $this->app->make($driverClass)
+ : $this->app->make(UsernameDriver::class);
+ });
+
+ $this->app->alias('flarum.user.display_name.driver', DriverInterface::class);
}
protected function registerGate()
@@ -84,6 +112,7 @@ class UserServiceProvider extends AbstractServiceProvider
User::setHasher($this->app->make('hash'));
User::setGate($this->app->make('flarum.gate'));
+ User::setDisplayNameDriver($this->app->make('flarum.user.display_name.driver'));
$events = $this->app->make('events');
diff --git a/framework/core/tests/integration/extenders/UserTest.php b/framework/core/tests/integration/extenders/UserTest.php
new file mode 100644
index 000000000..78449b373
--- /dev/null
+++ b/framework/core/tests/integration/extenders/UserTest.php
@@ -0,0 +1,69 @@
+prepareDatabase([
+ 'users' => [
+ $this->adminUser(),
+ ], 'settings' => [
+ ['key' => 'display_name_driver', 'value' => 'custom'],
+ ],
+ ]);
+ }
+
+ /**
+ * @test
+ */
+ public function username_display_name_driver_used_by_default()
+ {
+ $this->prepDb();
+
+ $user = User::find(1);
+
+ $this->assertEquals('admin', $user->displayName);
+ }
+
+ /**
+ * @test
+ */
+ public function can_use_custom_display_name_driver()
+ {
+ $this->extend(
+ (new Extend\User)
+ ->displayNameDriver('custom', CustomDisplayNameDriver::class)
+ );
+
+ $this->prepDb();
+
+ $user = User::find(1);
+
+ $this->assertEquals('admin@machine.local$$$suffix', $user->displayName);
+ }
+}
+
+class CustomDisplayNameDriver implements DriverInterface
+{
+ public function displayName(User $user): string
+ {
+ return $user->email.'$$$suffix';
+ }
+}