mirror of
https://github.com/flarum/core.git
synced 2025-08-13 03:44:32 +02:00
Compare commits
7 Commits
dk/2836-tr
...
dk/1236-us
Author | SHA1 | Date | |
---|---|---|---|
|
d95f22424d | ||
|
18fb20cdb7 | ||
|
ae55cd3d20 | ||
|
23736fcfda | ||
|
3046461c77 | ||
|
46e049ecb0 | ||
|
49d8559599 |
@@ -0,0 +1,28 @@
|
||||
<?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.
|
||||
*/
|
||||
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Schema\Builder;
|
||||
|
||||
return [
|
||||
'up' => function (Builder $schema) {
|
||||
$schema->create('notification_preferences', function (Blueprint $table) {
|
||||
$table->integer('user_id')->unsigned();
|
||||
$table->string('type');
|
||||
$table->string('channel');
|
||||
$table->boolean('enabled')->default(false);
|
||||
|
||||
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
|
||||
});
|
||||
},
|
||||
|
||||
'down' => function (Builder $schema) {
|
||||
$schema->drop('notification_preferences');
|
||||
}
|
||||
];
|
@@ -0,0 +1,27 @@
|
||||
<?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.
|
||||
*/
|
||||
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Schema\Builder;
|
||||
|
||||
return [
|
||||
'up' => function (Builder $schema) {
|
||||
$schema->table('users', function (Blueprint $table) {
|
||||
$table->boolean('disclose_online')->default(false);
|
||||
$table->string('locale')->nullable();
|
||||
});
|
||||
},
|
||||
|
||||
'down' => function (Builder $schema) {
|
||||
$schema->table('users', function (Blueprint $table) {
|
||||
$table->dropColumn('disclose_online');
|
||||
$table->dropColumn('locale');
|
||||
});
|
||||
}
|
||||
];
|
@@ -0,0 +1,52 @@
|
||||
<?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.
|
||||
*/
|
||||
|
||||
use Illuminate\Database\Schema\Builder;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
return [
|
||||
'up' => function (Builder $builder) {
|
||||
$db = $builder->getConnection();
|
||||
|
||||
$db->table('users')
|
||||
->select(['id', 'preferences'])
|
||||
->whereNotNull('preferences')
|
||||
->orderBy('id')
|
||||
->each(function ($user) use ($db) {
|
||||
collect(json_decode($user->preferences ?? '{}'))
|
||||
->each(function ($value, $key) use ($user, $db) {
|
||||
if (in_array($key, ['discloseOnline', 'followAfterReply'])) {
|
||||
$db->table('users')
|
||||
->where('id', $user->id)
|
||||
->update([Str::snake($key) => (bool) $value]);
|
||||
}
|
||||
if ($key === 'locale') {
|
||||
$db->table('users')
|
||||
->where('id', $user->id)
|
||||
->update(['locale' => $value]);
|
||||
}
|
||||
if (preg_match('/^notify_(?<type>[^_]+)_(?<channel>.*)$/', $key, $matches)) {
|
||||
$db->table('notification_preferences')
|
||||
->insert([
|
||||
'user_id' => $user->id,
|
||||
'type' => $matches['type'],
|
||||
'channel' => $matches['channel'],
|
||||
'enabled' => (bool) $value
|
||||
]);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
'down' => function (Builder $builder) {
|
||||
$db = $builder->getConnection();
|
||||
|
||||
$db->table('notification_preferences')->truncate();
|
||||
}
|
||||
];
|
@@ -0,0 +1,25 @@
|
||||
<?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.
|
||||
*/
|
||||
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Schema\Builder;
|
||||
|
||||
return [
|
||||
'up' => function (Builder $schema) {
|
||||
$schema->table('users', function (Blueprint $table) {
|
||||
$table->dropColumn('preferences');
|
||||
});
|
||||
},
|
||||
|
||||
'down' => function (Builder $schema) {
|
||||
$schema->table('users', function (Blueprint $table) {
|
||||
$table->binary('preferences')->nullable();
|
||||
});
|
||||
}
|
||||
];
|
33
src/Extend/Notification.php
Normal file
33
src/Extend/Notification.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?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\User\NotificationPreference;
|
||||
use Illuminate\Contracts\Container\Container;
|
||||
|
||||
class Notification implements ExtenderInterface
|
||||
{
|
||||
private $channels = [];
|
||||
|
||||
public function extend(Container $container, Extension $extension = null)
|
||||
{
|
||||
foreach ($this->channels as $channel => $enabled) {
|
||||
NotificationPreference::addChannel($channel, $enabled ?? []);
|
||||
}
|
||||
}
|
||||
|
||||
public function addChannel(string $channel, array $enabledTypes = null)
|
||||
{
|
||||
$this->channels[$channel] = $enabledTypes;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
@@ -10,6 +10,7 @@
|
||||
namespace Flarum\Extend;
|
||||
|
||||
use Flarum\Extension\Extension;
|
||||
use Flarum\User\User as Eloquent;
|
||||
use Illuminate\Contracts\Container\Container;
|
||||
|
||||
class User implements ExtenderInterface
|
||||
@@ -35,4 +36,11 @@ class User implements ExtenderInterface
|
||||
return array_merge($existingDrivers, $this->drivers);
|
||||
});
|
||||
}
|
||||
|
||||
public function addPreference(string $key, callable $transformer = null, $default = null)
|
||||
{
|
||||
Eloquent::addPreference($key, $transformer, $default);
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
36
src/User/Concerns/DeprecatedUserNotificationPreferences.php
Normal file
36
src/User/Concerns/DeprecatedUserNotificationPreferences.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?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\User\Concerns;
|
||||
|
||||
trait DeprecatedUserNotificationPreferences
|
||||
{
|
||||
/**
|
||||
* Encode an array of preferences for storage in the database.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @deprecated 0.1.0-beta.13: `users.preferences` is no longer used.
|
||||
*/
|
||||
public function setPreferencesAttribute($value)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the key for a preference which flags whether or not the user will
|
||||
* receive a notification for $type via $method.
|
||||
*
|
||||
* @param string $type
|
||||
* @param string $method
|
||||
* @return string
|
||||
* @deprecated 0.1.0-beta.13: `users.preferences` is no longer used, use \Flarum\User\NotificationPreference.
|
||||
*/
|
||||
public static function getNotificationPreferenceKey($type, $method)
|
||||
{
|
||||
}
|
||||
}
|
87
src/User/Concerns/UserPreferences.php
Normal file
87
src/User/Concerns/UserPreferences.php
Normal file
@@ -0,0 +1,87 @@
|
||||
<?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\User\Concerns;
|
||||
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
trait UserPreferences
|
||||
{
|
||||
/**
|
||||
* An array of registered user preferences. Each preference is defined with
|
||||
* a key, and its value is an array containing the following keys:.
|
||||
*
|
||||
* - transformer: a callback that confines the value of the preference
|
||||
* - default: a default value if the preference isn't set
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $preferences = [];
|
||||
|
||||
/**
|
||||
* Get the values of all registered preferences for this user, by
|
||||
* transforming their stored preferences and merging them with the defaults.
|
||||
*
|
||||
* @param string $value
|
||||
* @return array
|
||||
*/
|
||||
public function getPreferencesAttribute($value)
|
||||
{
|
||||
$defaults = array_map(function ($value) {
|
||||
return $value['default'];
|
||||
}, static::$preferences);
|
||||
|
||||
$user = Arr::only($this->notificationPreferences->toArray(), array_keys(static::$preferences));
|
||||
|
||||
return array_merge($defaults, $user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of a preference for this user.
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $default
|
||||
* @return mixed
|
||||
*/
|
||||
public function getPreference($key, $default = null)
|
||||
{
|
||||
return $this->$key ?? $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of a preference for this user.
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function setPreference($key, $value)
|
||||
{
|
||||
$preference = static::$preferences[$key];
|
||||
|
||||
// If a user preference is registered, transform the value.
|
||||
if ($preference) {
|
||||
$value = $value === null ? $preference['default'] : $value;
|
||||
$value = $preference['transformer']($value);
|
||||
}
|
||||
|
||||
$this->{$key} = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a preference with a transformer and a default value.
|
||||
*
|
||||
* @param string $key
|
||||
* @param callable $transformer
|
||||
* @param mixed $default
|
||||
*/
|
||||
public static function addPreference($key, callable $transformer = null, $default = null)
|
||||
{
|
||||
static::$preferences[$key] = compact('transformer', 'default');
|
||||
}
|
||||
}
|
75
src/User/NotificationPreference.php
Normal file
75
src/User/NotificationPreference.php
Normal file
@@ -0,0 +1,75 @@
|
||||
<?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\User;
|
||||
|
||||
use Flarum\Database\AbstractModel;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* @property int $user_id
|
||||
* @property string $type
|
||||
* @property string $channel
|
||||
* @property bool $enabled
|
||||
*/
|
||||
class NotificationPreference extends AbstractModel
|
||||
{
|
||||
protected static $channels = [];
|
||||
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
|
||||
public static function addChannel(string $channel, array $defaults = [])
|
||||
{
|
||||
static::$channels[$channel] = $defaults;
|
||||
}
|
||||
|
||||
public static function getNotificationPreferences(User $user, string $channel = null, string $type = null)
|
||||
{
|
||||
$saved = $user->notificationPreferences()
|
||||
->when('type', function ($query, $type) {
|
||||
$query->where('type', $type);
|
||||
})
|
||||
->whereIn('channel', $channel ? [$channel] : array_keys(static::$channels))
|
||||
->get();
|
||||
|
||||
if ($channel && $type) {
|
||||
return $saved->first();
|
||||
}
|
||||
|
||||
return $saved;
|
||||
}
|
||||
|
||||
public static function setNotificationPreference(User $user, string $channel, string $type, bool $enabled = true)
|
||||
{
|
||||
if (array_key_exists($channel, static::$channels)) {
|
||||
$attributes = [
|
||||
'channel' => $channel,
|
||||
'type' => $type
|
||||
];
|
||||
|
||||
$user->notificationPreferences()->updateOrInsert($attributes, ['enabled' => $enabled]);
|
||||
} else {
|
||||
throw new InvalidArgumentException("Channel '$channel' is not registered.");
|
||||
}
|
||||
}
|
||||
|
||||
public function scopeShouldBeNotified(Builder $query, string $type, string $channel = null)
|
||||
{
|
||||
return $query
|
||||
->where('enabled', true)
|
||||
->where('type', $type)
|
||||
->when($channel, function ($query, $channel) {
|
||||
$query->where('channel', $channel);
|
||||
});
|
||||
}
|
||||
}
|
@@ -36,7 +36,6 @@ use Flarum\User\Event\Registered;
|
||||
use Flarum\User\Event\Renamed;
|
||||
use Illuminate\Contracts\Hashing\Hasher;
|
||||
use Illuminate\Contracts\Session\Session;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
@@ -58,6 +57,8 @@ class User extends AbstractModel
|
||||
{
|
||||
use EventGeneratorTrait;
|
||||
use ScopeVisibilityTrait;
|
||||
use Concerns\DeprecatedUserNotificationPreferences;
|
||||
use Concerns\UserPreferences;
|
||||
|
||||
/**
|
||||
* The attributes that should be mutated to dates.
|
||||
@@ -457,34 +458,6 @@ class User extends AbstractModel
|
||||
})->count();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the values of all registered preferences for this user, by
|
||||
* transforming their stored preferences and merging them with the defaults.
|
||||
*
|
||||
* @param string $value
|
||||
* @return array
|
||||
*/
|
||||
public function getPreferencesAttribute($value)
|
||||
{
|
||||
$defaults = array_map(function ($value) {
|
||||
return $value['default'];
|
||||
}, static::$preferences);
|
||||
|
||||
$user = Arr::only((array) json_decode($value, true), array_keys(static::$preferences));
|
||||
|
||||
return array_merge($defaults, $user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode an array of preferences for storage in the database.
|
||||
*
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function setPreferencesAttribute($value)
|
||||
{
|
||||
$this->attributes['preferences'] = json_encode($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether or not the user should receive an alert for a notification
|
||||
* type.
|
||||
@@ -509,42 +482,6 @@ class User extends AbstractModel
|
||||
return (bool) $this->getPreference(static::getNotificationPreferenceKey($type, 'email'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of a preference for this user.
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $default
|
||||
* @return mixed
|
||||
*/
|
||||
public function getPreference($key, $default = null)
|
||||
{
|
||||
return Arr::get($this->preferences, $key, $default);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of a preference for this user.
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @return $this
|
||||
*/
|
||||
public function setPreference($key, $value)
|
||||
{
|
||||
if (isset(static::$preferences[$key])) {
|
||||
$preferences = $this->preferences;
|
||||
|
||||
if (! is_null($transformer = static::$preferences[$key]['transformer'])) {
|
||||
$preferences[$key] = call_user_func($transformer, $value);
|
||||
} else {
|
||||
$preferences[$key] = $value;
|
||||
}
|
||||
|
||||
$this->preferences = $preferences;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the user as being last seen just now.
|
||||
*
|
||||
@@ -622,6 +559,11 @@ class User extends AbstractModel
|
||||
return $this->belongsToMany(Group::class)->where('is_hidden', false);
|
||||
}
|
||||
|
||||
public function notificationPreferences()
|
||||
{
|
||||
return $this->hasMany(NotificationPreference::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the relationship with the user's notifications.
|
||||
*
|
||||
@@ -739,31 +681,6 @@ class User extends AbstractModel
|
||||
static::$hasher = $hasher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a preference with a transformer and a default value.
|
||||
*
|
||||
* @param string $key
|
||||
* @param callable $transformer
|
||||
* @param mixed $default
|
||||
*/
|
||||
public static function addPreference($key, callable $transformer = null, $default = null)
|
||||
{
|
||||
static::$preferences[$key] = compact('transformer', 'default');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the key for a preference which flags whether or not the user will
|
||||
* receive a notification for $type via $method.
|
||||
*
|
||||
* @param string $type
|
||||
* @param string $method
|
||||
* @return string
|
||||
*/
|
||||
public static function getNotificationPreferenceKey($type, $method)
|
||||
{
|
||||
return 'notify_'.$type.'_'.$method;
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the user's comments count.
|
||||
*
|
||||
|
57
tests/integration/extenders/NotificationChannelTest.php
Normal file
57
tests/integration/extenders/NotificationChannelTest.php
Normal file
@@ -0,0 +1,57 @@
|
||||
<?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\Extend\Notification;
|
||||
use Flarum\Tests\integration\RetrievesAuthorizedUsers;
|
||||
use Flarum\Tests\integration\TestCase;
|
||||
use Flarum\User\NotificationPreference;
|
||||
use Flarum\User\User;
|
||||
|
||||
class NotificationChannelTest extends TestCase
|
||||
{
|
||||
use RetrievesAuthorizedUsers;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->prepareDatabase([
|
||||
'users' => [
|
||||
$this->normalUser()
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
private function add_channel()
|
||||
{
|
||||
$this->extend((new Notification)->addChannel('test'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function can_enable_notification_channel()
|
||||
{
|
||||
$this->add_channel();
|
||||
|
||||
/** @var User $user */
|
||||
$user = User::find(2);
|
||||
|
||||
NotificationPreference::setNotificationPreference($user, 'test', 'newPost');
|
||||
|
||||
$this->assertTrue(
|
||||
$user->notificationPreferences()
|
||||
->where('channel', 'test')
|
||||
->where('type', 'newPost')
|
||||
->get('enabled')
|
||||
);
|
||||
}
|
||||
}
|
67
tests/integration/extenders/UserPreferencesTest.php
Normal file
67
tests/integration/extenders/UserPreferencesTest.php
Normal file
@@ -0,0 +1,67 @@
|
||||
<?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\Extend\User as Extender;
|
||||
use Flarum\Tests\integration\RetrievesAuthorizedUsers;
|
||||
use Flarum\Tests\integration\TestCase;
|
||||
use Flarum\User\User;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
class UserPreferencesTest extends TestCase
|
||||
{
|
||||
use RetrievesAuthorizedUsers;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->prepareDatabase([
|
||||
'users' => [
|
||||
$this->normalUser()
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
private function add_preference()
|
||||
{
|
||||
$this->extend(
|
||||
(new Extender())
|
||||
->addPreference('test', 'boolval', false)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function can_add_user_preference()
|
||||
{
|
||||
$this->add_preference();
|
||||
|
||||
/** @var User $user */
|
||||
$user = User::find(2);
|
||||
$this->assertEquals(false, Arr::get($user->preferences, 'test'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function can_store_user_preference()
|
||||
{
|
||||
$this->add_preference();
|
||||
|
||||
/** @var User $user */
|
||||
$user = User::find(2);
|
||||
|
||||
$user->setPreference('test', true);
|
||||
|
||||
$this->assertEquals(true, $user->test);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user