mirror of
https://github.com/flarum/core.git
synced 2025-10-14 00:15:51 +02:00
Major refactor and improvements
- Reorganised all namespaces and class names for consistency and structure. Following PSR bylaws (Abstract prefix, Interface/Trait suffix). - Move models into root of Core, because writing `use Flarum\Core\Discussion` is nice. Namespace the rest by type. (Namespacing by entity was too arbitrary.) - Moved some non-domain stuff out of Core: Database, Formatter, Settings. - Renamed config table and all references to "settings" for consistency. - Remove Core class and add url()/isInstalled()/inDebugMode() as instance methods of Foundation\Application. - Cleanup, docblocking, etc. - Improvements to HTTP architecture - API and forum/admin Actions are now actually all the same thing (simple PSR-7 Request handlers), renamed to Controllers. - Upgrade to tobscure/json-api 0.2 branch. - Where possible, moved generic functionality to tobscure/json-api (e.g. pagination links). I'm quite happy with the backend balance now re: #262 - Improvements to other architecture - Use Illuminate's Auth\Access\Gate interface/implementation instead of our old Locked trait. We still use events to actually determine the permissions though. Our Policy classes are actually glorified event subscribers. - Extract model validation into Core\Validator classes. - Make post visibility permission stuff much more efficient and DRY. - Renamed Flarum\Event classes for consistency. ref #246 - `Configure` prefix for events dedicated to configuring an object. - `Get` prefix for events whose listeners should return something. - `Prepare` prefix when a variable is passed by reference so it can be modified. - `Scope` prefix when a query builder is passed. - Miscellaneous improvements/bug-fixes. I'm easily distracted! - Increase default height of post composer. - Improve post stream redraw flickering in Safari by keying loading post placeholders with their IDs. ref #451 - Use a PHP JavaScript minification library for minifying TextFormatter's JavaScript, instead of ClosureCompilerService (can't rely on external service!) - Use UrlGenerator properly in various places. closes #123 - Make Api\Client return Response object. closes #128 - Allow extensions to specify custom icon images. - Allow external API/admin URLs to be optionally specified in config.php. If the value or "url" is an array, we look for the corresponding path inside. Otherwise, we append the path to the base URL, using the corresponding value in "paths" if present. closes #244
This commit is contained in:
67
src/Core/Access/AbstractPolicy.php
Normal file
67
src/Core/Access/AbstractPolicy.php
Normal file
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* (c) Toby Zerner <toby.zerner@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Access;
|
||||
|
||||
use Flarum\Event\GetPermission;
|
||||
use Flarum\Event\ScopeModelVisibility;
|
||||
use Illuminate\Contracts\Events\Dispatcher;
|
||||
|
||||
abstract class AbstractPolicy
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $model;
|
||||
|
||||
/**
|
||||
* @param Dispatcher $events
|
||||
*/
|
||||
public function subscribe(Dispatcher $events)
|
||||
{
|
||||
$events->listen(GetPermission::class, [$this, 'getPermission']);
|
||||
$events->listen(ScopeModelVisibility::class, [$this, 'scopeModelVisibility']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param GetPermission $event
|
||||
* @return bool|null
|
||||
*/
|
||||
public function getPermission(GetPermission $event)
|
||||
{
|
||||
if (isset($event->arguments[0]) && $event->arguments[0] instanceof $this->model) {
|
||||
if (method_exists($this, 'before')) {
|
||||
$arguments = array_merge([$event->actor, $event->ability], $event->arguments);
|
||||
|
||||
$result = call_user_func_array([$this, 'before'], $arguments);
|
||||
|
||||
if (! is_null($result)) {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
if (method_exists($this, $event->ability)) {
|
||||
$arguments = array_merge([$event->actor], $event->arguments);
|
||||
|
||||
return call_user_func_array([$this, $event->ability], $arguments);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ScopeModelVisibility $event
|
||||
*/
|
||||
public function scopeModelVisibility(ScopeModelVisibility $event)
|
||||
{
|
||||
if ($event->model instanceof $this->model && method_exists($this, 'find')) {
|
||||
call_user_func_array([$this, 'find'], [$event->actor, $event->query]);
|
||||
}
|
||||
}
|
||||
}
|
66
src/Core/Access/AssertPermissionTrait.php
Normal file
66
src/Core/Access/AssertPermissionTrait.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* (c) Toby Zerner <toby.zerner@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Access;
|
||||
|
||||
use Flarum\Core\Exception\PermissionDeniedException;
|
||||
use Flarum\Core\User;
|
||||
|
||||
trait AssertPermissionTrait
|
||||
{
|
||||
/**
|
||||
* @param $condition
|
||||
* @throws PermissionDeniedException
|
||||
*/
|
||||
protected function assertPermission($condition)
|
||||
{
|
||||
if (! $condition) {
|
||||
throw new PermissionDeniedException;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $actor
|
||||
* @param string $ability
|
||||
* @param mixed $arguments
|
||||
* @throws PermissionDeniedException
|
||||
*/
|
||||
protected function assertCan(User $actor, $ability, $arguments = [])
|
||||
{
|
||||
$this->assertPermission($actor->can($ability, $arguments));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $actor
|
||||
* @throws PermissionDeniedException
|
||||
*/
|
||||
protected function assertGuest(User $actor)
|
||||
{
|
||||
$this->assertPermission($actor->isGuest());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $actor
|
||||
* @throws PermissionDeniedException
|
||||
*/
|
||||
protected function assertRegistered(User $actor)
|
||||
{
|
||||
$this->assertPermission(! $actor->isGuest());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $actor
|
||||
* @throws PermissionDeniedException
|
||||
*/
|
||||
protected function assertAdmin(User $actor)
|
||||
{
|
||||
$this->assertPermission($actor->isAdmin());
|
||||
}
|
||||
}
|
112
src/Core/Access/DiscussionPolicy.php
Normal file
112
src/Core/Access/DiscussionPolicy.php
Normal file
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* (c) Toby Zerner <toby.zerner@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Access;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Flarum\Core\Discussion;
|
||||
use Flarum\Core\User;
|
||||
use Flarum\Event\ScopeHiddenDiscussionVisibility;
|
||||
use Flarum\Settings\SettingsRepository;
|
||||
use Illuminate\Contracts\Events\Dispatcher;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class DiscussionPolicy extends AbstractPolicy
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $model = Discussion::class;
|
||||
|
||||
/**
|
||||
* @var SettingsRepository
|
||||
*/
|
||||
protected $settings;
|
||||
|
||||
/**
|
||||
* @var Gate
|
||||
*/
|
||||
protected $gate;
|
||||
|
||||
/**
|
||||
* @var Dispatcher
|
||||
*/
|
||||
protected $events;
|
||||
|
||||
/**
|
||||
* @param SettingsRepository $settings
|
||||
* @param Gate $gate
|
||||
*/
|
||||
public function __construct(SettingsRepository $settings, Gate $gate, Dispatcher $events)
|
||||
{
|
||||
$this->settings = $settings;
|
||||
$this->gate = $gate;
|
||||
$this->events = $events;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $actor
|
||||
* @param string $ability
|
||||
* @return bool|null
|
||||
*/
|
||||
public function before(User $actor, $ability)
|
||||
{
|
||||
if ($actor->hasPermission('discussion.'.$ability)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $actor
|
||||
* @param Builder $query
|
||||
*/
|
||||
public function find(User $actor, Builder $query)
|
||||
{
|
||||
if (! $actor->hasPermission('discussion.hide')) {
|
||||
$query->where(function ($query) use ($actor) {
|
||||
$query->whereNull('discussions.hide_time')
|
||||
->where('comments_count', '>', 0)
|
||||
->orWhere('start_user_id', $actor->id);
|
||||
|
||||
$this->events->fire(
|
||||
new ScopeHiddenDiscussionVisibility($query, $actor, 'discussion.hide')
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $actor
|
||||
* @param Discussion $discussion
|
||||
* @return bool|null
|
||||
*/
|
||||
public function rename(User $actor, Discussion $discussion)
|
||||
{
|
||||
if ($discussion->start_user_id == $actor->id) {
|
||||
$allowRenaming = $this->settings->get('allow_renaming');
|
||||
|
||||
if ($allowRenaming === '-1'
|
||||
|| ($allowRenaming === 'reply' && $discussion->participants_count <= 1)
|
||||
|| ($discussion->start_time->diffInMinutes(new Carbon) < $allowRenaming)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $actor
|
||||
* @param Discussion $discussion
|
||||
* @return bool|null
|
||||
*/
|
||||
public function delete(User $actor, Discussion $discussion)
|
||||
{
|
||||
return $this->rename($actor, $discussion);
|
||||
}
|
||||
}
|
345
src/Core/Access/Gate.php
Normal file
345
src/Core/Access/Gate.php
Normal file
@@ -0,0 +1,345 @@
|
||||
<?php
|
||||
|
||||
namespace Flarum\Core\Access;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Illuminate\Contracts\Container\Container;
|
||||
use Illuminate\Contracts\Auth\Access\Gate as GateContract;
|
||||
|
||||
/**
|
||||
* @author Taylor Otwell
|
||||
*/
|
||||
class Gate implements GateContract
|
||||
{
|
||||
/**
|
||||
* The container instance.
|
||||
*
|
||||
* @var Container
|
||||
*/
|
||||
protected $container;
|
||||
|
||||
/**
|
||||
* The user resolver callable.
|
||||
*
|
||||
* @var callable
|
||||
*/
|
||||
protected $userResolver;
|
||||
|
||||
/**
|
||||
* All of the defined abilities.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $abilities = [];
|
||||
|
||||
/**
|
||||
* All of the defined policies.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $policies = [];
|
||||
|
||||
/**
|
||||
* All of the registered before callbacks.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $beforeCallbacks = [];
|
||||
|
||||
/**
|
||||
* Create a new gate instance.
|
||||
*
|
||||
* @param Container $container
|
||||
* @param callable $userResolver
|
||||
* @param array $abilities
|
||||
* @param array $policies
|
||||
* @param array $beforeCallbacks
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Container $container, callable $userResolver, array $abilities = [], array $policies = [], array $beforeCallbacks = [])
|
||||
{
|
||||
$this->policies = $policies;
|
||||
$this->container = $container;
|
||||
$this->abilities = $abilities;
|
||||
$this->userResolver = $userResolver;
|
||||
$this->beforeCallbacks = $beforeCallbacks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a given ability has been defined.
|
||||
*
|
||||
* @param string $ability
|
||||
* @return bool
|
||||
*/
|
||||
public function has($ability)
|
||||
{
|
||||
return isset($this->abilities[$ability]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Define a new ability.
|
||||
*
|
||||
* @param string $ability
|
||||
* @param callable|string $callback
|
||||
* @return $this
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function define($ability, $callback)
|
||||
{
|
||||
if (is_callable($callback)) {
|
||||
$this->abilities[$ability] = $callback;
|
||||
} elseif (is_string($callback) && str_contains($callback, '@')) {
|
||||
$this->abilities[$ability] = $this->buildAbilityCallback($callback);
|
||||
} else {
|
||||
throw new InvalidArgumentException("Callback must be a callable or a 'Class@method' string.");
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the ability callback for a callback string.
|
||||
*
|
||||
* @param string $callback
|
||||
* @return \Closure
|
||||
*/
|
||||
protected function buildAbilityCallback($callback)
|
||||
{
|
||||
return function () use ($callback) {
|
||||
list($class, $method) = explode('@', $callback);
|
||||
|
||||
return call_user_func_array([$this->resolvePolicy($class), $method], func_get_args());
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Define a policy class for a given class type.
|
||||
*
|
||||
* @param string $class
|
||||
* @param string $policy
|
||||
* @return $this
|
||||
*/
|
||||
public function policy($class, $policy)
|
||||
{
|
||||
$this->policies[$class] = $policy;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a callback to run before all Gate checks.
|
||||
*
|
||||
* @param callable $callback
|
||||
* @return $this
|
||||
*/
|
||||
public function before(callable $callback)
|
||||
{
|
||||
$this->beforeCallbacks[] = $callback;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given ability should be granted for the current user.
|
||||
*
|
||||
* @param string $ability
|
||||
* @param array|mixed $arguments
|
||||
* @return bool
|
||||
*/
|
||||
public function allows($ability, $arguments = [])
|
||||
{
|
||||
return $this->check($ability, $arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given ability should be denied for the current user.
|
||||
*
|
||||
* @param string $ability
|
||||
* @param array|mixed $arguments
|
||||
* @return bool
|
||||
*/
|
||||
public function denies($ability, $arguments = [])
|
||||
{
|
||||
return ! $this->allows($ability, $arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given ability should be granted for the current user.
|
||||
*
|
||||
* @param string $ability
|
||||
* @param array|mixed $arguments
|
||||
* @return bool
|
||||
*/
|
||||
public function check($ability, $arguments = [])
|
||||
{
|
||||
if (! $user = $this->resolveUser()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$arguments = is_array($arguments) ? $arguments : [$arguments];
|
||||
|
||||
if (! is_null($result = $this->callBeforeCallbacks($user, $ability, $arguments))) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$callback = $this->resolveAuthCallback(
|
||||
$user, $ability, $arguments
|
||||
);
|
||||
|
||||
return call_user_func_array($callback, array_merge([$user], $arguments));
|
||||
}
|
||||
|
||||
/**
|
||||
* Call all of the before callbacks and return if a result is given.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Auth\Authenticatable $user
|
||||
* @param string $ability
|
||||
* @param array $arguments
|
||||
* @return bool|void
|
||||
*/
|
||||
protected function callBeforeCallbacks($user, $ability, array $arguments)
|
||||
{
|
||||
$arguments = array_merge([$user, $ability], $arguments);
|
||||
|
||||
foreach ($this->beforeCallbacks as $before) {
|
||||
if (! is_null($result = call_user_func_array($before, $arguments))) {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the callable for the given ability and arguments.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Auth\Authenticatable $user
|
||||
* @param string $ability
|
||||
* @param array $arguments
|
||||
* @return callable
|
||||
*/
|
||||
protected function resolveAuthCallback($user, $ability, array $arguments)
|
||||
{
|
||||
if ($this->firstArgumentCorrespondsToPolicy($arguments)) {
|
||||
return $this->resolvePolicyCallback($user, $ability, $arguments);
|
||||
} elseif (isset($this->abilities[$ability])) {
|
||||
return $this->abilities[$ability];
|
||||
} else {
|
||||
return function () { return false; };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the first argument in the array corresponds to a policy.
|
||||
*
|
||||
* @param array $arguments
|
||||
* @return bool
|
||||
*/
|
||||
protected function firstArgumentCorrespondsToPolicy(array $arguments)
|
||||
{
|
||||
if (! isset($arguments[0])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_object($arguments[0])) {
|
||||
return isset($this->policies[get_class($arguments[0])]);
|
||||
}
|
||||
|
||||
return is_string($arguments[0]) && isset($this->policies[$arguments[0]]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the callback for a policy check.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Auth\Authenticatable $user
|
||||
* @param string $ability
|
||||
* @param array $arguments
|
||||
* @return callable
|
||||
*/
|
||||
protected function resolvePolicyCallback($user, $ability, array $arguments)
|
||||
{
|
||||
return function () use ($user, $ability, $arguments) {
|
||||
$instance = $this->getPolicyFor($arguments[0]);
|
||||
|
||||
if (method_exists($instance, 'before')) {
|
||||
// We will prepend the user and ability onto the arguments so that the before
|
||||
// callback can determine which ability is being called. Then we will call
|
||||
// into the policy before methods with the arguments and get the result.
|
||||
$beforeArguments = array_merge([$user, $ability], $arguments);
|
||||
|
||||
$result = call_user_func_array(
|
||||
[$instance, 'before'], $beforeArguments
|
||||
);
|
||||
|
||||
// If we recieved a non-null result from the before method, we will return it
|
||||
// as the result of a check. This allows developers to override the checks
|
||||
// in the policy and return a result for all rules defined in the class.
|
||||
if (! is_null($result)) {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
if (! is_callable([$instance, $ability])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return call_user_func_array(
|
||||
[$instance, $ability], array_merge([$user], $arguments)
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a policy instance for a given class.
|
||||
*
|
||||
* @param object|string $class
|
||||
* @return mixed
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function getPolicyFor($class)
|
||||
{
|
||||
if (is_object($class)) {
|
||||
$class = get_class($class);
|
||||
}
|
||||
|
||||
if (! isset($this->policies[$class])) {
|
||||
throw new InvalidArgumentException("Policy not defined for [{$class}].");
|
||||
}
|
||||
|
||||
return $this->resolvePolicy($this->policies[$class]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a policy class instance of the given type.
|
||||
*
|
||||
* @param object|string $class
|
||||
* @return mixed
|
||||
*/
|
||||
public function resolvePolicy($class)
|
||||
{
|
||||
return $this->container->make($class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a guard instance for the given user.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Auth\Authenticatable|mixed $user
|
||||
* @return static
|
||||
*/
|
||||
public function forUser($user)
|
||||
{
|
||||
return new static(
|
||||
$this->container, function () use ($user) { return $user; }, $this->abilities, $this->policies, $this->beforeCallbacks
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the user from the user resolver.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function resolveUser()
|
||||
{
|
||||
return call_user_func($this->userResolver);
|
||||
}
|
||||
}
|
34
src/Core/Access/GroupPolicy.php
Normal file
34
src/Core/Access/GroupPolicy.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* (c) Toby Zerner <toby.zerner@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Access;
|
||||
|
||||
use Flarum\Core\Group;
|
||||
use Flarum\Core\User;
|
||||
|
||||
class GroupPolicy extends AbstractPolicy
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $model = Group::class;
|
||||
|
||||
/**
|
||||
* @param User $actor
|
||||
* @param string $ability
|
||||
* @return bool|null
|
||||
*/
|
||||
public function before(User $actor, $ability)
|
||||
{
|
||||
if ($actor->hasPermission('group.'.$ability)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
121
src/Core/Access/PostPolicy.php
Normal file
121
src/Core/Access/PostPolicy.php
Normal file
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* (c) Toby Zerner <toby.zerner@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Access;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Flarum\Core\Post;
|
||||
use Flarum\Core\User;
|
||||
use Flarum\Event\ScopePostVisibility;
|
||||
use Flarum\Settings\SettingsRepository;
|
||||
use Illuminate\Contracts\Events\Dispatcher;
|
||||
|
||||
class PostPolicy extends AbstractPolicy
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $model = Post::class;
|
||||
|
||||
/**
|
||||
* @var SettingsRepository
|
||||
*/
|
||||
protected $settings;
|
||||
|
||||
/**
|
||||
* @var Gate
|
||||
*/
|
||||
protected $gate;
|
||||
|
||||
/**
|
||||
* @param SettingsRepository $settings
|
||||
* @param Gate $gate
|
||||
*/
|
||||
public function __construct(SettingsRepository $settings, Gate $gate)
|
||||
{
|
||||
$this->settings = $settings;
|
||||
$this->gate = $gate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function subscribe(Dispatcher $events)
|
||||
{
|
||||
parent::subscribe($events);
|
||||
|
||||
$events->listen(ScopePostVisibility::class, [$this, 'scopePostVisibility']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $actor
|
||||
* @param string $ability
|
||||
* @param Post $post
|
||||
* @return bool|null
|
||||
*/
|
||||
public function before(User $actor, $ability, Post $post)
|
||||
{
|
||||
if ($this->discussionAllows($actor, $ability, $post)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ScopePostVisibility $event
|
||||
*/
|
||||
public function scopePostVisibility(ScopePostVisibility $event)
|
||||
{
|
||||
// When fetching a discussion's posts: if the user doesn't have permission
|
||||
// to moderate the discussion, then they can't see posts that have been
|
||||
// hidden by someone other than themself.
|
||||
if ($this->gate->forUser($event->actor)->denies('editPosts', $event->discussion)) {
|
||||
$event->query->where(function ($query) use ($event) {
|
||||
$query->whereNull('hide_time')
|
||||
->orWhere('user_id', $event->actor->id);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $actor
|
||||
* @param Post $post
|
||||
* @return bool|null
|
||||
*/
|
||||
public function edit(User $actor, Post $post)
|
||||
{
|
||||
if ($this->discussionAllows($actor, 'edit', $post)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// A post is allowed to be edited if the user has permission to moderate
|
||||
// the discussion which it's in, or if they are the author and the post
|
||||
// hasn't been deleted by someone else.
|
||||
if ($post->user_id == $actor->id && (! $post->hide_time || $post->hide_user_id == $actor->id)) {
|
||||
$allowEditing = $this->settings->get('allow_post_editing');
|
||||
|
||||
if ($allowEditing === '-1'
|
||||
|| ($allowEditing === 'reply' && $post->number >= $post->discussion->last_post_number)
|
||||
|| ($post->time->diffInMinutes(new Carbon) < $allowEditing)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $actor
|
||||
* @param string $ability
|
||||
* @param Post $post
|
||||
* @return bool
|
||||
*/
|
||||
protected function discussionAllows(User $actor, $ability, Post $post)
|
||||
{
|
||||
return $this->gate->forUser($actor)->allows($ability.'Posts', $post->discussion);
|
||||
}
|
||||
}
|
34
src/Core/Access/UserPolicy.php
Normal file
34
src/Core/Access/UserPolicy.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* (c) Toby Zerner <toby.zerner@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Access;
|
||||
|
||||
use Flarum\Core\User;
|
||||
|
||||
class UserPolicy extends AbstractPolicy
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $model = User::class;
|
||||
|
||||
/**
|
||||
* @param User $actor
|
||||
* @param string $ability
|
||||
* @return bool|null
|
||||
*/
|
||||
public function before(User $actor, $ability)
|
||||
{
|
||||
if ($actor->hasPermission('user.'.$ability)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -8,16 +8,16 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Users;
|
||||
namespace Flarum\Core;
|
||||
|
||||
use Flarum\Core\Model;
|
||||
use Flarum\Core\Exceptions\InvalidConfirmationTokenException;
|
||||
use Flarum\Database\AbstractModel;
|
||||
use Flarum\Core\Exception\InvalidConfirmationTokenException;
|
||||
use DateTime;
|
||||
|
||||
/**
|
||||
* @todo document database columns with @property
|
||||
*/
|
||||
class AuthToken extends Model
|
||||
class AuthToken extends AbstractModel
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
@@ -8,7 +8,7 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Users\Commands;
|
||||
namespace Flarum\Core\Command;
|
||||
|
||||
class ConfirmEmail
|
||||
{
|
@@ -8,17 +8,16 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Users\Commands;
|
||||
namespace Flarum\Core\Command;
|
||||
|
||||
use Flarum\Core\Users\UserRepository;
|
||||
use Flarum\Events\UserWillBeSaved;
|
||||
use Flarum\Core\Support\DispatchesEvents;
|
||||
use Flarum\Core\Users\EmailToken;
|
||||
use DateTime;
|
||||
use Flarum\Core\EmailToken;
|
||||
use Flarum\Core\Repository\UserRepository;
|
||||
use Flarum\Core\Support\DispatchEventsTrait;
|
||||
use Illuminate\Contracts\Events\Dispatcher;
|
||||
|
||||
class ConfirmEmailHandler
|
||||
{
|
||||
use DispatchesEvents;
|
||||
use DispatchEventsTrait;
|
||||
|
||||
/**
|
||||
* @var UserRepository
|
||||
@@ -28,20 +27,19 @@ class ConfirmEmailHandler
|
||||
/**
|
||||
* @param UserRepository $users
|
||||
*/
|
||||
public function __construct(UserRepository $users)
|
||||
public function __construct(Dispatcher $events, UserRepository $users)
|
||||
{
|
||||
$this->events = $events;
|
||||
$this->users = $users;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ConfirmEmail $command
|
||||
*
|
||||
* @throws InvalidConfirmationTokenException
|
||||
*
|
||||
* @return \Flarum\Core\Users\User
|
||||
* @return \Flarum\Core\User
|
||||
*/
|
||||
public function handle(ConfirmEmail $command)
|
||||
{
|
||||
/** @var EmailToken $token */
|
||||
$token = EmailToken::validOrFail($command->token);
|
||||
|
||||
$user = $token->user;
|
@@ -8,9 +8,9 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Groups\Commands;
|
||||
namespace Flarum\Core\Command;
|
||||
|
||||
use Flarum\Core\Users\User;
|
||||
use Flarum\Core\User;
|
||||
|
||||
class CreateGroup
|
||||
{
|
@@ -8,40 +8,39 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Groups\Commands;
|
||||
namespace Flarum\Core\Command;
|
||||
|
||||
use Flarum\Core\Groups\Group;
|
||||
use Flarum\Core\Forum;
|
||||
use Flarum\Events\GroupWillBeSaved;
|
||||
use Flarum\Core\Support\DispatchesEvents;
|
||||
use Flarum\Core\Access\AssertPermissionTrait;
|
||||
use Flarum\Core\Exception\PermissionDeniedException;
|
||||
use Flarum\Core\Group;
|
||||
use Flarum\Event\GroupWillBeSaved;
|
||||
use Flarum\Core\Support\DispatchEventsTrait;
|
||||
use Illuminate\Contracts\Events\Dispatcher;
|
||||
|
||||
class CreateGroupHandler
|
||||
{
|
||||
use DispatchesEvents;
|
||||
use DispatchEventsTrait;
|
||||
use AssertPermissionTrait;
|
||||
|
||||
/**
|
||||
* @var Forum
|
||||
* @param Dispatcher $events
|
||||
*/
|
||||
protected $forum;
|
||||
|
||||
/**
|
||||
* @param Forum $forum
|
||||
*/
|
||||
public function __construct(Forum $forum)
|
||||
public function __construct(Dispatcher $events)
|
||||
{
|
||||
$this->forum = $forum;
|
||||
$this->events = $events;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param CreateGroup $command
|
||||
* @return Group
|
||||
* @throws PermissionDeniedException
|
||||
*/
|
||||
public function handle(CreateGroup $command)
|
||||
{
|
||||
$actor = $command->actor;
|
||||
$data = $command->data;
|
||||
|
||||
$this->forum->assertCan($actor, 'createGroup');
|
||||
$this->assertCan($actor, 'createGroup');
|
||||
|
||||
$group = Group::build(
|
||||
array_get($data, 'attributes.nameSingular'),
|
||||
@@ -50,10 +49,13 @@ class CreateGroupHandler
|
||||
array_get($data, 'attributes.icon')
|
||||
);
|
||||
|
||||
event(new GroupWillBeSaved($group, $actor, $data));
|
||||
$this->events->fire(
|
||||
new GroupWillBeSaved($group, $actor, $data)
|
||||
);
|
||||
|
||||
$group->save();
|
||||
$this->dispatchEventsFor($group);
|
||||
|
||||
$this->dispatchEventsFor($group, $actor);
|
||||
|
||||
return $group;
|
||||
}
|
@@ -8,9 +8,9 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Users\Commands;
|
||||
namespace Flarum\Core\Command;
|
||||
|
||||
use Flarum\Core\Users\User;
|
||||
use Flarum\Core\User;
|
||||
|
||||
class DeleteAvatar
|
||||
{
|
@@ -8,16 +8,20 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Users\Commands;
|
||||
namespace Flarum\Core\Command;
|
||||
|
||||
use Flarum\Events\AvatarWillBeDeleted;
|
||||
use Flarum\Core\Users\UserRepository;
|
||||
use Flarum\Core\Support\DispatchesEvents;
|
||||
use Flarum\Core\Access\AssertPermissionTrait;
|
||||
use Flarum\Core\Exception\PermissionDeniedException;
|
||||
use Flarum\Event\AvatarWillBeDeleted;
|
||||
use Flarum\Core\Repository\UserRepository;
|
||||
use Flarum\Core\Support\DispatchEventsTrait;
|
||||
use Illuminate\Contracts\Events\Dispatcher;
|
||||
use League\Flysystem\FilesystemInterface;
|
||||
|
||||
class DeleteAvatarHandler
|
||||
{
|
||||
use DispatchesEvents;
|
||||
use DispatchEventsTrait;
|
||||
use AssertPermissionTrait;
|
||||
|
||||
/**
|
||||
* @var UserRepository
|
||||
@@ -30,18 +34,21 @@ class DeleteAvatarHandler
|
||||
protected $uploadDir;
|
||||
|
||||
/**
|
||||
* @param Dispatcher $events
|
||||
* @param UserRepository $users
|
||||
* @param FilesystemInterface $uploadDir
|
||||
*/
|
||||
public function __construct(UserRepository $users, FilesystemInterface $uploadDir)
|
||||
public function __construct(Dispatcher $events, UserRepository $users, FilesystemInterface $uploadDir)
|
||||
{
|
||||
$this->events = $events;
|
||||
$this->users = $users;
|
||||
$this->uploadDir = $uploadDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DeleteAvatar $command
|
||||
* @return \Flarum\Core\Users\User
|
||||
* @return \Flarum\Core\User
|
||||
* @throws PermissionDeniedException
|
||||
*/
|
||||
public function handle(DeleteAvatar $command)
|
||||
{
|
||||
@@ -49,24 +56,24 @@ class DeleteAvatarHandler
|
||||
|
||||
$user = $this->users->findOrFail($command->userId);
|
||||
|
||||
// Make sure the current user is allowed to edit the user profile.
|
||||
// This will let admins and the user themselves pass through, and
|
||||
// throw an exception otherwise.
|
||||
if ($actor->id !== $user->id) {
|
||||
$user->assertCan($actor, 'edit');
|
||||
$this->assertCan($actor, 'edit', $user);
|
||||
}
|
||||
|
||||
$avatarPath = $user->avatar_path;
|
||||
$user->changeAvatarPath(null);
|
||||
|
||||
event(new AvatarWillBeDeleted($user, $actor));
|
||||
$this->events->fire(
|
||||
new AvatarWillBeDeleted($user, $actor)
|
||||
);
|
||||
|
||||
$user->save();
|
||||
|
||||
if ($this->uploadDir->has($avatarPath)) {
|
||||
$this->uploadDir->delete($avatarPath);
|
||||
}
|
||||
|
||||
$user->save();
|
||||
$this->dispatchEventsFor($user);
|
||||
$this->dispatchEventsFor($user, $actor);
|
||||
|
||||
return $user;
|
||||
}
|
@@ -8,9 +8,9 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Discussions\Commands;
|
||||
namespace Flarum\Core\Command;
|
||||
|
||||
use Flarum\Core\Users\User;
|
||||
use Flarum\Core\User;
|
||||
|
||||
class DeleteDiscussion
|
||||
{
|
63
src/Core/Command/DeleteDiscussionHandler.php
Normal file
63
src/Core/Command/DeleteDiscussionHandler.php
Normal file
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* (c) Toby Zerner <toby.zerner@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Command;
|
||||
|
||||
use Flarum\Core\Access\AssertPermissionTrait;
|
||||
use Flarum\Core\Exception\PermissionDeniedException;
|
||||
use Flarum\Core\Repository\DiscussionRepository;
|
||||
use Flarum\Core\Support\DispatchEventsTrait;
|
||||
use Flarum\Event\DiscussionWillBeDeleted;
|
||||
use Illuminate\Contracts\Events\Dispatcher;
|
||||
|
||||
class DeleteDiscussionHandler
|
||||
{
|
||||
use DispatchEventsTrait;
|
||||
use AssertPermissionTrait;
|
||||
|
||||
/**
|
||||
* @var DiscussionRepository
|
||||
*/
|
||||
protected $discussions;
|
||||
|
||||
/**
|
||||
* @param Dispatcher $events
|
||||
* @param DiscussionRepository $discussions
|
||||
*/
|
||||
public function __construct(Dispatcher $events, DiscussionRepository $discussions)
|
||||
{
|
||||
$this->events = $events;
|
||||
$this->discussions = $discussions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DeleteDiscussion $command
|
||||
* @return \Flarum\Core\Discussion
|
||||
* @throws PermissionDeniedException
|
||||
*/
|
||||
public function handle(DeleteDiscussion $command)
|
||||
{
|
||||
$actor = $command->actor;
|
||||
|
||||
$discussion = $this->discussions->findOrFail($command->discussionId, $actor);
|
||||
|
||||
$this->assertCan($actor, 'delete', $discussion);
|
||||
|
||||
$this->events->fire(
|
||||
new DiscussionWillBeDeleted($discussion, $actor, $command->data)
|
||||
);
|
||||
|
||||
$discussion->delete();
|
||||
|
||||
$this->dispatchEventsFor($discussion, $actor);
|
||||
|
||||
return $discussion;
|
||||
}
|
||||
}
|
@@ -8,10 +8,10 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Groups\Commands;
|
||||
namespace Flarum\Core\Command;
|
||||
|
||||
use Flarum\Core\Groups\Group;
|
||||
use Flarum\Core\Users\User;
|
||||
use Flarum\Core\Group;
|
||||
use Flarum\Core\User;
|
||||
|
||||
class DeleteGroup
|
||||
{
|
62
src/Core/Command/DeleteGroupHandler.php
Normal file
62
src/Core/Command/DeleteGroupHandler.php
Normal file
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* (c) Toby Zerner <toby.zerner@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Command;
|
||||
|
||||
use Flarum\Core\Access\AssertPermissionTrait;
|
||||
use Flarum\Core\Exception\PermissionDeniedException;
|
||||
use Flarum\Core\Repository\GroupRepository;
|
||||
use Flarum\Event\GroupWillBeDeleted;
|
||||
use Flarum\Core\Support\DispatchEventsTrait;
|
||||
use Illuminate\Contracts\Events\Dispatcher;
|
||||
|
||||
class DeleteGroupHandler
|
||||
{
|
||||
use DispatchEventsTrait;
|
||||
use AssertPermissionTrait;
|
||||
|
||||
/**
|
||||
* @var GroupRepository
|
||||
*/
|
||||
protected $groups;
|
||||
|
||||
/**
|
||||
* @param GroupRepository $groups
|
||||
*/
|
||||
public function __construct(Dispatcher $events, GroupRepository $groups)
|
||||
{
|
||||
$this->groups = $groups;
|
||||
$this->events = $events;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DeleteGroup $command
|
||||
* @return \Flarum\Core\Group
|
||||
* @throws PermissionDeniedException
|
||||
*/
|
||||
public function handle(DeleteGroup $command)
|
||||
{
|
||||
$actor = $command->actor;
|
||||
|
||||
$group = $this->groups->findOrFail($command->groupId, $actor);
|
||||
|
||||
$this->assertCan($actor, 'delete', $group);
|
||||
|
||||
$this->events->fire(
|
||||
new GroupWillBeDeleted($group, $actor, $command->data)
|
||||
);
|
||||
|
||||
$group->delete();
|
||||
|
||||
$this->dispatchEventsFor($group, $actor);
|
||||
|
||||
return $group;
|
||||
}
|
||||
}
|
@@ -8,9 +8,9 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Posts\Commands;
|
||||
namespace Flarum\Core\Command;
|
||||
|
||||
use Flarum\Core\Users\User;
|
||||
use Flarum\Core\User;
|
||||
|
||||
class DeletePost
|
||||
{
|
63
src/Core/Command/DeletePostHandler.php
Normal file
63
src/Core/Command/DeletePostHandler.php
Normal file
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* (c) Toby Zerner <toby.zerner@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Command;
|
||||
|
||||
use Flarum\Core\Access\AssertPermissionTrait;
|
||||
use Flarum\Core\Exception\PermissionDeniedException;
|
||||
use Flarum\Core\Repository\PostRepository;
|
||||
use Flarum\Event\PostWillBeDeleted;
|
||||
use Flarum\Core\Support\DispatchEventsTrait;
|
||||
use Illuminate\Contracts\Events\Dispatcher;
|
||||
|
||||
class DeletePostHandler
|
||||
{
|
||||
use DispatchEventsTrait;
|
||||
use AssertPermissionTrait;
|
||||
|
||||
/**
|
||||
* @var PostRepository
|
||||
*/
|
||||
protected $posts;
|
||||
|
||||
/**
|
||||
* @param Dispatcher $events
|
||||
* @param PostRepository $posts
|
||||
*/
|
||||
public function __construct(Dispatcher $events, PostRepository $posts)
|
||||
{
|
||||
$this->events = $events;
|
||||
$this->posts = $posts;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DeletePost $command
|
||||
* @return \Flarum\Core\Post
|
||||
* @throws PermissionDeniedException
|
||||
*/
|
||||
public function handle(DeletePost $command)
|
||||
{
|
||||
$actor = $command->actor;
|
||||
|
||||
$post = $this->posts->findOrFail($command->postId, $actor);
|
||||
|
||||
$this->assertCan($actor, 'delete', $post);
|
||||
|
||||
$this->events->fire(
|
||||
new PostWillBeDeleted($post, $actor, $command->data)
|
||||
);
|
||||
|
||||
$post->delete();
|
||||
|
||||
$this->dispatchEventsFor($post, $actor);
|
||||
|
||||
return $post;
|
||||
}
|
||||
}
|
@@ -8,9 +8,9 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Users\Commands;
|
||||
namespace Flarum\Core\Command;
|
||||
|
||||
use Flarum\Core\Users\User;
|
||||
use Flarum\Core\User;
|
||||
|
||||
class DeleteUser
|
||||
{
|
62
src/Core/Command/DeleteUserHandler.php
Normal file
62
src/Core/Command/DeleteUserHandler.php
Normal file
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* (c) Toby Zerner <toby.zerner@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Command;
|
||||
|
||||
use Flarum\Core\Access\AssertPermissionTrait;
|
||||
use Flarum\Core\Exception\PermissionDeniedException;
|
||||
use Flarum\Core\Repository\UserRepository;
|
||||
use Flarum\Event\UserWillBeDeleted;
|
||||
use Flarum\Core\Support\DispatchEventsTrait;
|
||||
use Illuminate\Contracts\Events\Dispatcher;
|
||||
|
||||
class DeleteUserHandler
|
||||
{
|
||||
use DispatchEventsTrait;
|
||||
use AssertPermissionTrait;
|
||||
|
||||
/**
|
||||
* @var UserRepository
|
||||
*/
|
||||
protected $users;
|
||||
|
||||
/**
|
||||
* @param Dispatcher $events
|
||||
* @param UserRepository $users
|
||||
*/
|
||||
public function __construct(Dispatcher $events, UserRepository $users)
|
||||
{
|
||||
$this->events = $events;
|
||||
$this->users = $users;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DeleteUser $command
|
||||
* @return \Flarum\Core\User
|
||||
* @throws PermissionDeniedException
|
||||
*/
|
||||
public function handle(DeleteUser $command)
|
||||
{
|
||||
$actor = $command->actor;
|
||||
$user = $this->users->findOrFail($command->userId, $actor);
|
||||
|
||||
$this->assertCan($actor, 'delete', $user);
|
||||
|
||||
$this->events->fire(
|
||||
new UserWillBeDeleted($user, $actor, $command->data)
|
||||
);
|
||||
|
||||
$user->delete();
|
||||
|
||||
$this->dispatchEventsFor($user, $actor);
|
||||
|
||||
return $user;
|
||||
}
|
||||
}
|
@@ -8,9 +8,9 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Discussions\Commands;
|
||||
namespace Flarum\Core\Command;
|
||||
|
||||
use Flarum\Core\Users\User;
|
||||
use Flarum\Core\User;
|
||||
|
||||
class EditDiscussion
|
||||
{
|
||||
@@ -24,7 +24,7 @@ class EditDiscussion
|
||||
/**
|
||||
* The user performing the action.
|
||||
*
|
||||
* @var \Flarum\Core\Users\User
|
||||
* @var \Flarum\Core\User
|
||||
*/
|
||||
public $actor;
|
||||
|
||||
@@ -37,7 +37,7 @@ class EditDiscussion
|
||||
|
||||
/**
|
||||
* @param integer $discussionId The ID of the discussion to edit.
|
||||
* @param \Flarum\Core\Users\User $actor The user performing the action.
|
||||
* @param \Flarum\Core\User $actor The user performing the action.
|
||||
* @param array $data The attributes to update on the discussion.
|
||||
*/
|
||||
public function __construct($discussionId, User $actor, array $data)
|
@@ -8,15 +8,19 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Discussions\Commands;
|
||||
namespace Flarum\Core\Command;
|
||||
|
||||
use Flarum\Core\Discussions\DiscussionRepository;
|
||||
use Flarum\Events\DiscussionWillBeSaved;
|
||||
use Flarum\Core\Support\DispatchesEvents;
|
||||
use Flarum\Core\Access\AssertPermissionTrait;
|
||||
use Flarum\Core\Exception\PermissionDeniedException;
|
||||
use Flarum\Core\Repository\DiscussionRepository;
|
||||
use Flarum\Core\Support\DispatchEventsTrait;
|
||||
use Flarum\Event\DiscussionWillBeSaved;
|
||||
use Illuminate\Contracts\Events\Dispatcher;
|
||||
|
||||
class EditDiscussionHandler
|
||||
{
|
||||
use DispatchesEvents;
|
||||
use DispatchEventsTrait;
|
||||
use AssertPermissionTrait;
|
||||
|
||||
/**
|
||||
* @var DiscussionRepository
|
||||
@@ -24,17 +28,19 @@ class EditDiscussionHandler
|
||||
protected $discussions;
|
||||
|
||||
/**
|
||||
* @param Dispatcher $events
|
||||
* @param DiscussionRepository $discussions
|
||||
*/
|
||||
public function __construct(DiscussionRepository $discussions)
|
||||
public function __construct(Dispatcher $events, DiscussionRepository $discussions)
|
||||
{
|
||||
$this->events = $events;
|
||||
$this->discussions = $discussions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param EditDiscussion $command
|
||||
* @return \Flarum\Core\Discussions\Discussion
|
||||
* @throws \Flarum\Core\Exceptions\PermissionDeniedException
|
||||
* @return \Flarum\Core\Discussion
|
||||
* @throws PermissionDeniedException
|
||||
*/
|
||||
public function handle(EditDiscussion $command)
|
||||
{
|
||||
@@ -45,12 +51,13 @@ class EditDiscussionHandler
|
||||
$discussion = $this->discussions->findOrFail($command->discussionId, $actor);
|
||||
|
||||
if (isset($attributes['title'])) {
|
||||
$discussion->assertCan($actor, 'rename');
|
||||
$discussion->rename($attributes['title'], $actor);
|
||||
$this->assertCan($actor, 'rename', $discussion);
|
||||
|
||||
$discussion->rename($attributes['title']);
|
||||
}
|
||||
|
||||
if (isset($attributes['isHidden'])) {
|
||||
$discussion->assertCan($actor, 'hide');
|
||||
$this->assertCan($actor, 'hide', $discussion);
|
||||
|
||||
if ($attributes['isHidden']) {
|
||||
$discussion->hide($actor);
|
||||
@@ -59,11 +66,13 @@ class EditDiscussionHandler
|
||||
}
|
||||
}
|
||||
|
||||
event(new DiscussionWillBeSaved($discussion, $actor, $data));
|
||||
$this->events->fire(
|
||||
new DiscussionWillBeSaved($discussion, $actor, $data)
|
||||
);
|
||||
|
||||
$discussion->save();
|
||||
|
||||
$this->dispatchEventsFor($discussion);
|
||||
$this->dispatchEventsFor($discussion, $actor);
|
||||
|
||||
return $discussion;
|
||||
}
|
@@ -8,10 +8,10 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Groups\Commands;
|
||||
namespace Flarum\Core\Command;
|
||||
|
||||
use Flarum\Core\Groups\Group;
|
||||
use Flarum\Core\Users\User;
|
||||
use Flarum\Core\Group;
|
||||
use Flarum\Core\User;
|
||||
|
||||
class EditGroup
|
||||
{
|
@@ -8,16 +8,20 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Groups\Commands;
|
||||
namespace Flarum\Core\Command;
|
||||
|
||||
use Flarum\Core\Groups\Group;
|
||||
use Flarum\Core\Groups\GroupRepository;
|
||||
use Flarum\Events\GroupWillBeSaved;
|
||||
use Flarum\Core\Support\DispatchesEvents;
|
||||
use Flarum\Core\Access\AssertPermissionTrait;
|
||||
use Flarum\Core\Exception\PermissionDeniedException;
|
||||
use Flarum\Core\Group;
|
||||
use Flarum\Core\Repository\GroupRepository;
|
||||
use Flarum\Event\GroupWillBeSaved;
|
||||
use Flarum\Core\Support\DispatchEventsTrait;
|
||||
use Illuminate\Contracts\Events\Dispatcher;
|
||||
|
||||
class EditGroupHandler
|
||||
{
|
||||
use DispatchesEvents;
|
||||
use DispatchEventsTrait;
|
||||
use AssertPermissionTrait;
|
||||
|
||||
/**
|
||||
* @var GroupRepository
|
||||
@@ -25,17 +29,19 @@ class EditGroupHandler
|
||||
protected $groups;
|
||||
|
||||
/**
|
||||
* @param Dispatcher $events
|
||||
* @param GroupRepository $groups
|
||||
*/
|
||||
public function __construct(GroupRepository $groups)
|
||||
public function __construct(Dispatcher $events, GroupRepository $groups)
|
||||
{
|
||||
$this->events = $events;
|
||||
$this->groups = $groups;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param EditGroup $command
|
||||
* @return Group
|
||||
* @throws \Flarum\Core\Exceptions\PermissionDeniedException
|
||||
* @throws PermissionDeniedException
|
||||
*/
|
||||
public function handle(EditGroup $command)
|
||||
{
|
||||
@@ -44,7 +50,7 @@ class EditGroupHandler
|
||||
|
||||
$group = $this->groups->findOrFail($command->groupId, $actor);
|
||||
|
||||
$group->assertCan($actor, 'edit');
|
||||
$this->assertCan($actor, 'edit', $group);
|
||||
|
||||
$attributes = array_get($data, 'attributes', []);
|
||||
|
||||
@@ -60,10 +66,13 @@ class EditGroupHandler
|
||||
$group->icon = $attributes['icon'];
|
||||
}
|
||||
|
||||
event(new GroupWillBeSaved($group, $actor, $data));
|
||||
$this->events->fire(
|
||||
new GroupWillBeSaved($group, $actor, $data)
|
||||
);
|
||||
|
||||
$group->save();
|
||||
$this->dispatchEventsFor($group);
|
||||
|
||||
$this->dispatchEventsFor($group, $actor);
|
||||
|
||||
return $group;
|
||||
}
|
@@ -8,9 +8,9 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Posts\Commands;
|
||||
namespace Flarum\Core\Command;
|
||||
|
||||
use Flarum\Core\Users\User;
|
||||
use Flarum\Core\User;
|
||||
|
||||
class EditPost
|
||||
{
|
@@ -8,16 +8,19 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Posts\Commands;
|
||||
namespace Flarum\Core\Command;
|
||||
|
||||
use Flarum\Core\Posts\PostRepository;
|
||||
use Flarum\Events\PostWillBeSaved;
|
||||
use Flarum\Core\Support\DispatchesEvents;
|
||||
use Flarum\Core\Posts\CommentPost;
|
||||
use Flarum\Core\Access\AssertPermissionTrait;
|
||||
use Flarum\Core\Repository\PostRepository;
|
||||
use Flarum\Event\PostWillBeSaved;
|
||||
use Flarum\Core\Support\DispatchEventsTrait;
|
||||
use Flarum\Core\Post\CommentPost;
|
||||
use Illuminate\Contracts\Events\Dispatcher;
|
||||
|
||||
class EditPostHandler
|
||||
{
|
||||
use DispatchesEvents;
|
||||
use DispatchEventsTrait;
|
||||
use AssertPermissionTrait;
|
||||
|
||||
/**
|
||||
* @var PostRepository
|
||||
@@ -25,17 +28,19 @@ class EditPostHandler
|
||||
protected $posts;
|
||||
|
||||
/**
|
||||
* @param Dispatcher $events
|
||||
* @param PostRepository $posts
|
||||
*/
|
||||
public function __construct(PostRepository $posts)
|
||||
public function __construct(Dispatcher $events, PostRepository $posts)
|
||||
{
|
||||
$this->events = $events;
|
||||
$this->posts = $posts;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param EditPost $command
|
||||
* @return \Flarum\Core\Posts\Post
|
||||
* @throws \Flarum\Core\Exceptions\PermissionDeniedException
|
||||
* @return \Flarum\Core\Post
|
||||
* @throws \Flarum\Core\Exception\PermissionDeniedException
|
||||
*/
|
||||
public function handle(EditPost $command)
|
||||
{
|
||||
@@ -48,13 +53,13 @@ class EditPostHandler
|
||||
$attributes = array_get($data, 'attributes', []);
|
||||
|
||||
if (isset($attributes['content'])) {
|
||||
$post->assertCan($actor, 'edit');
|
||||
$this->assertCan($actor, 'edit', $post);
|
||||
|
||||
$post->revise($attributes['content'], $actor);
|
||||
}
|
||||
|
||||
if (isset($attributes['isHidden'])) {
|
||||
$post->assertCan($actor, 'edit');
|
||||
$this->assertCan($actor, 'edit', $post);
|
||||
|
||||
if ($attributes['isHidden']) {
|
||||
$post->hide($actor);
|
||||
@@ -64,11 +69,13 @@ class EditPostHandler
|
||||
}
|
||||
}
|
||||
|
||||
event(new PostWillBeSaved($post, $actor, $data));
|
||||
$this->events->fire(
|
||||
new PostWillBeSaved($post, $actor, $data)
|
||||
);
|
||||
|
||||
$post->save();
|
||||
|
||||
$this->dispatchEventsFor($post);
|
||||
$this->dispatchEventsFor($post, $actor);
|
||||
|
||||
return $post;
|
||||
}
|
@@ -8,9 +8,9 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Users\Commands;
|
||||
namespace Flarum\Core\Command;
|
||||
|
||||
use Flarum\Core\Users\User;
|
||||
use Flarum\Core\User;
|
||||
|
||||
class EditUser
|
||||
{
|
@@ -8,18 +8,20 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Users\Commands;
|
||||
namespace Flarum\Core\Command;
|
||||
|
||||
use Flarum\Core\Users\User;
|
||||
use Flarum\Core\Users\UserRepository;
|
||||
use Flarum\Events\UserWillBeSaved;
|
||||
use Flarum\Events\UserGroupsWereChanged;
|
||||
use Flarum\Core\Support\DispatchesEvents;
|
||||
use Flarum\Core\Exceptions\PermissionDeniedException;
|
||||
use Flarum\Core\Access\AssertPermissionTrait;
|
||||
use Flarum\Core\User;
|
||||
use Flarum\Core\Repository\UserRepository;
|
||||
use Flarum\Event\UserWillBeSaved;
|
||||
use Flarum\Event\UserGroupsWereChanged;
|
||||
use Flarum\Core\Support\DispatchEventsTrait;
|
||||
use Illuminate\Contracts\Events\Dispatcher;
|
||||
|
||||
class EditUserHandler
|
||||
{
|
||||
use DispatchesEvents;
|
||||
use DispatchEventsTrait;
|
||||
use AssertPermissionTrait;
|
||||
|
||||
/**
|
||||
* @var UserRepository
|
||||
@@ -27,17 +29,19 @@ class EditUserHandler
|
||||
protected $users;
|
||||
|
||||
/**
|
||||
* @param Dispatcher $events
|
||||
* @param UserRepository $users
|
||||
*/
|
||||
public function __construct(UserRepository $users)
|
||||
public function __construct(Dispatcher $events, UserRepository $users)
|
||||
{
|
||||
$this->events = $events;
|
||||
$this->users = $users;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param EditUser $command
|
||||
* @return User
|
||||
* @throws \Flarum\Core\Exceptions\PermissionDeniedException
|
||||
* @throws \Flarum\Core\Exception\PermissionDeniedException
|
||||
*/
|
||||
public function handle(EditUser $command)
|
||||
{
|
||||
@@ -45,13 +49,15 @@ class EditUserHandler
|
||||
$data = $command->data;
|
||||
|
||||
$user = $this->users->findOrFail($command->userId, $actor);
|
||||
|
||||
$canEdit = $actor->can('edit', $user);
|
||||
$isSelf = $actor->id === $user->id;
|
||||
|
||||
$attributes = array_get($data, 'attributes', []);
|
||||
$relationships = array_get($data, 'relationships', []);
|
||||
|
||||
if (isset($attributes['username'])) {
|
||||
$user->assertCan($actor, 'edit');
|
||||
$this->assertPermission($canEdit);
|
||||
$user->rename($attributes['username']);
|
||||
}
|
||||
|
||||
@@ -59,31 +65,31 @@ class EditUserHandler
|
||||
if ($isSelf) {
|
||||
$user->requestEmailChange($attributes['email']);
|
||||
} else {
|
||||
$user->assertCan($actor, 'edit');
|
||||
$this->assertPermission($canEdit);
|
||||
$user->changeEmail($attributes['email']);
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($attributes['password'])) {
|
||||
$user->assertCan($actor, 'edit');
|
||||
$this->assertPermission($canEdit);
|
||||
$user->changePassword($attributes['password']);
|
||||
}
|
||||
|
||||
if (isset($attributes['bio'])) {
|
||||
if (! $isSelf) {
|
||||
$user->assertCan($actor, 'edit');
|
||||
$this->assertPermission($canEdit);
|
||||
}
|
||||
|
||||
$user->changeBio($attributes['bio']);
|
||||
}
|
||||
|
||||
if (! empty($attributes['readTime'])) {
|
||||
$this->assert($isSelf);
|
||||
$this->assertPermission($isSelf);
|
||||
$user->markAllAsRead();
|
||||
}
|
||||
|
||||
if (! empty($attributes['preferences'])) {
|
||||
$this->assert($isSelf);
|
||||
$this->assertPermission($isSelf);
|
||||
|
||||
foreach ($attributes['preferences'] as $k => $v) {
|
||||
$user->setPreference($k, $v);
|
||||
@@ -91,7 +97,7 @@ class EditUserHandler
|
||||
}
|
||||
|
||||
if (isset($relationships['groups']['data']) && is_array($relationships['groups']['data'])) {
|
||||
$user->assertCan($actor, 'edit');
|
||||
$this->assertPermission($canEdit);
|
||||
|
||||
$newGroupIds = [];
|
||||
foreach ($relationships['groups']['data'] as $group) {
|
||||
@@ -100,25 +106,23 @@ class EditUserHandler
|
||||
}
|
||||
}
|
||||
|
||||
$user->raise(new UserGroupsWereChanged($user, $user->groups()->get()->all()));
|
||||
$user->raise(
|
||||
new UserGroupsWereChanged($user, $user->groups()->get()->all())
|
||||
);
|
||||
|
||||
User::saved(function ($user) use ($newGroupIds) {
|
||||
$user->afterSave(function (User $user) use ($newGroupIds) {
|
||||
$user->groups()->sync($newGroupIds);
|
||||
});
|
||||
}
|
||||
|
||||
event(new UserWillBeSaved($user, $actor, $data));
|
||||
$this->events->fire(
|
||||
new UserWillBeSaved($user, $actor, $data)
|
||||
);
|
||||
|
||||
$user->save();
|
||||
$this->dispatchEventsFor($user);
|
||||
|
||||
$this->dispatchEventsFor($user, $actor);
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
protected function assert($true)
|
||||
{
|
||||
if (! $true) {
|
||||
throw new PermissionDeniedException;
|
||||
}
|
||||
}
|
||||
}
|
@@ -8,9 +8,9 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Posts\Commands;
|
||||
namespace Flarum\Core\Command;
|
||||
|
||||
use Flarum\Core\Users\User;
|
||||
use Flarum\Core\User;
|
||||
|
||||
class PostReply
|
||||
{
|
@@ -8,17 +8,20 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Posts\Commands;
|
||||
namespace Flarum\Core\Command;
|
||||
|
||||
use Flarum\Events\PostWillBeSaved;
|
||||
use Flarum\Core\Discussions\DiscussionRepository;
|
||||
use Flarum\Core\Posts\CommentPost;
|
||||
use Flarum\Core\Support\DispatchesEvents;
|
||||
use Flarum\Core\Notifications\NotificationSyncer;
|
||||
use Flarum\Core\Access\AssertPermissionTrait;
|
||||
use Flarum\Event\PostWillBeSaved;
|
||||
use Flarum\Core\Repository\DiscussionRepository;
|
||||
use Flarum\Core\Post\CommentPost;
|
||||
use Flarum\Core\Support\DispatchEventsTrait;
|
||||
use Flarum\Core\Notification\NotificationSyncer;
|
||||
use Illuminate\Contracts\Events\Dispatcher;
|
||||
|
||||
class PostReplyHandler
|
||||
{
|
||||
use DispatchesEvents;
|
||||
use DispatchEventsTrait;
|
||||
use AssertPermissionTrait;
|
||||
|
||||
/**
|
||||
* @var DiscussionRepository
|
||||
@@ -31,11 +34,16 @@ class PostReplyHandler
|
||||
protected $notifications;
|
||||
|
||||
/**
|
||||
* @param Dispatcher $events
|
||||
* @param DiscussionRepository $discussions
|
||||
* @param NotificationSyncer $notifications
|
||||
*/
|
||||
public function __construct(DiscussionRepository $discussions, NotificationSyncer $notifications)
|
||||
{
|
||||
public function __construct(
|
||||
Dispatcher $events,
|
||||
DiscussionRepository $discussions,
|
||||
NotificationSyncer $notifications
|
||||
) {
|
||||
$this->events = $events;
|
||||
$this->discussions = $discussions;
|
||||
$this->notifications = $notifications;
|
||||
}
|
||||
@@ -43,7 +51,7 @@ class PostReplyHandler
|
||||
/**
|
||||
* @param PostReply $command
|
||||
* @return CommentPost
|
||||
* @throws \Flarum\Core\Exceptions\PermissionDeniedException
|
||||
* @throws \Flarum\Core\Exception\PermissionDeniedException
|
||||
*/
|
||||
public function handle(PostReply $command)
|
||||
{
|
||||
@@ -56,23 +64,25 @@ class PostReplyHandler
|
||||
// it, check if they have permission to reply.
|
||||
$discussion = $this->discussions->findOrFail($command->discussionId, $actor);
|
||||
|
||||
$discussion->assertCan($actor, 'reply');
|
||||
$this->assertCan($actor, 'reply', $discussion);
|
||||
|
||||
// Create a new Post entity, persist it, and dispatch domain events.
|
||||
// Before persistence, though, fire an event to give plugins an
|
||||
// opportunity to alter the post entity based on data in the command.
|
||||
$post = CommentPost::reply(
|
||||
$command->discussionId,
|
||||
$discussion->id,
|
||||
array_get($command->data, 'attributes.content'),
|
||||
$actor->id
|
||||
);
|
||||
|
||||
event(new PostWillBeSaved($post, $actor, $command->data));
|
||||
$this->events->fire(
|
||||
new PostWillBeSaved($post, $actor, $command->data)
|
||||
);
|
||||
|
||||
$post->save();
|
||||
|
||||
$this->notifications->onePerUser(function () use ($post) {
|
||||
$this->dispatchEventsFor($post);
|
||||
$this->notifications->onePerUser(function () use ($post, $actor) {
|
||||
$this->dispatchEventsFor($post, $actor);
|
||||
});
|
||||
|
||||
return $post;
|
@@ -8,9 +8,9 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Notifications\Commands;
|
||||
namespace Flarum\Core\Command;
|
||||
|
||||
use Flarum\Core\Users\User;
|
||||
use Flarum\Core\User;
|
||||
|
||||
class ReadAllNotifications
|
||||
{
|
@@ -8,13 +8,16 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Notifications\Commands;
|
||||
namespace Flarum\Core\Command;
|
||||
|
||||
use Flarum\Core\Notifications\Notification;
|
||||
use Flarum\Core\Notifications\NotificationRepository;
|
||||
use Flarum\Core\Access\AssertPermissionTrait;
|
||||
use Flarum\Core\Notification;
|
||||
use Flarum\Core\Repository\NotificationRepository;
|
||||
|
||||
class ReadAllNotificationsHandler
|
||||
{
|
||||
use AssertPermissionTrait;
|
||||
|
||||
/**
|
||||
* @var NotificationRepository
|
||||
*/
|
||||
@@ -30,16 +33,13 @@ class ReadAllNotificationsHandler
|
||||
|
||||
/**
|
||||
* @param ReadAllNotifications $command
|
||||
*
|
||||
* @return void
|
||||
* @throws \Flarum\Core\Exception\PermissionDeniedException
|
||||
*/
|
||||
public function handle(ReadAllNotifications $command)
|
||||
{
|
||||
$actor = $command->actor;
|
||||
|
||||
if ($actor->isGuest()) {
|
||||
throw new PermissionDeniedException;
|
||||
}
|
||||
$this->assertRegistered($actor);
|
||||
|
||||
$this->notifications->markAllAsRead($actor);
|
||||
}
|
@@ -8,9 +8,9 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Discussions\Commands;
|
||||
namespace Flarum\Core\Command;
|
||||
|
||||
use Flarum\Core\Users\User;
|
||||
use Flarum\Core\User;
|
||||
|
||||
class ReadDiscussion
|
||||
{
|
@@ -8,16 +8,18 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Discussions\Commands;
|
||||
namespace Flarum\Core\Command;
|
||||
|
||||
use Flarum\Core\Discussions\DiscussionRepository;
|
||||
use Flarum\Events\DiscussionStateWillBeSaved;
|
||||
use Flarum\Core\Exceptions\PermissionDeniedException;
|
||||
use Flarum\Core\Support\DispatchesEvents;
|
||||
use Flarum\Core\Access\AssertPermissionTrait;
|
||||
use Flarum\Core\Repository\DiscussionRepository;
|
||||
use Flarum\Core\Support\DispatchEventsTrait;
|
||||
use Flarum\Event\DiscussionStateWillBeSaved;
|
||||
use Illuminate\Contracts\Events\Dispatcher;
|
||||
|
||||
class ReadDiscussionHandler
|
||||
{
|
||||
use DispatchesEvents;
|
||||
use DispatchEventsTrait;
|
||||
use AssertPermissionTrait;
|
||||
|
||||
/**
|
||||
* @var DiscussionRepository
|
||||
@@ -25,32 +27,34 @@ class ReadDiscussionHandler
|
||||
protected $discussions;
|
||||
|
||||
/**
|
||||
* @param Dispatcher $events
|
||||
* @param DiscussionRepository $discussions
|
||||
*/
|
||||
public function __construct(DiscussionRepository $discussions)
|
||||
public function __construct(Dispatcher $events, DiscussionRepository $discussions)
|
||||
{
|
||||
$this->events = $events;
|
||||
$this->discussions = $discussions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ReadDiscussion $command
|
||||
* @return \Flarum\Core\Discussions\DiscussionState
|
||||
* @throws \Flarum\Core\Exceptions\PermissionDeniedException
|
||||
* @return \Flarum\Core\DiscussionState
|
||||
* @throws \Flarum\Core\Exception\PermissionDeniedException
|
||||
*/
|
||||
public function handle(ReadDiscussion $command)
|
||||
{
|
||||
$actor = $command->actor;
|
||||
|
||||
if (! $actor->exists) {
|
||||
throw new PermissionDeniedException;
|
||||
}
|
||||
$this->assertRegistered($actor);
|
||||
|
||||
$discussion = $this->discussions->findOrFail($command->discussionId, $actor);
|
||||
|
||||
$state = $discussion->stateFor($actor);
|
||||
$state->read($command->readNumber);
|
||||
|
||||
event(new DiscussionStateWillBeSaved($state));
|
||||
$this->events->fire(
|
||||
new DiscussionStateWillBeSaved($state)
|
||||
);
|
||||
|
||||
$state->save();
|
||||
|
@@ -8,9 +8,9 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Notifications\Commands;
|
||||
namespace Flarum\Core\Command;
|
||||
|
||||
use Flarum\Core\Users\User;
|
||||
use Flarum\Core\User;
|
||||
|
||||
class ReadNotification
|
||||
{
|
@@ -8,26 +8,25 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Notifications\Commands;
|
||||
namespace Flarum\Core\Command;
|
||||
|
||||
use Flarum\Core\Notifications\Notification;
|
||||
use Flarum\Core\Exceptions\PermissionDeniedException;
|
||||
use Flarum\Core\Support\DispatchesEvents;
|
||||
use Flarum\Core\Access\AssertPermissionTrait;
|
||||
use Flarum\Core\Notification;
|
||||
|
||||
class ReadNotificationHandler
|
||||
{
|
||||
use AssertPermissionTrait;
|
||||
|
||||
/**
|
||||
* @param ReadNotification $command
|
||||
* @return Notification
|
||||
* @throws \Flarum\Core\Exceptions\PermissionDeniedException
|
||||
* @return \Flarum\Core\Notification
|
||||
* @throws \Flarum\Core\Exception\PermissionDeniedException
|
||||
*/
|
||||
public function handle(ReadNotification $command)
|
||||
{
|
||||
$actor = $command->actor;
|
||||
|
||||
if ($actor->isGuest()) {
|
||||
throw new PermissionDeniedException;
|
||||
}
|
||||
$this->assertRegistered($actor);
|
||||
|
||||
$notification = Notification::where('user_id', $actor->id)->findOrFail($command->notificationId);
|
||||
|
@@ -8,9 +8,9 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Users\Commands;
|
||||
namespace Flarum\Core\Command;
|
||||
|
||||
use Flarum\Core\Users\User;
|
||||
use Flarum\Core\User;
|
||||
|
||||
class RegisterUser
|
||||
{
|
@@ -8,19 +8,21 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Users\Commands;
|
||||
namespace Flarum\Core\Command;
|
||||
|
||||
use Flarum\Core\Users\User;
|
||||
use Flarum\Core\Users\AuthToken;
|
||||
use Flarum\Events\UserWillBeSaved;
|
||||
use Flarum\Core\Support\DispatchesEvents;
|
||||
use Flarum\Core\Settings\SettingsRepository;
|
||||
use Flarum\Core\Exceptions\PermissionDeniedException;
|
||||
use DateTime;
|
||||
use Flarum\Core\Access\AssertPermissionTrait;
|
||||
use Flarum\Core\User;
|
||||
use Flarum\Core\AuthToken;
|
||||
use Flarum\Event\UserWillBeSaved;
|
||||
use Flarum\Core\Support\DispatchEventsTrait;
|
||||
use Flarum\Settings\SettingsRepository;
|
||||
use Flarum\Core\Exception\PermissionDeniedException;
|
||||
use Illuminate\Contracts\Events\Dispatcher;
|
||||
|
||||
class RegisterUserHandler
|
||||
{
|
||||
use DispatchesEvents;
|
||||
use DispatchEventsTrait;
|
||||
use AssertPermissionTrait;
|
||||
|
||||
/**
|
||||
* @var SettingsRepository
|
||||
@@ -28,21 +30,21 @@ class RegisterUserHandler
|
||||
protected $settings;
|
||||
|
||||
/**
|
||||
* @param Dispatcher $events
|
||||
* @param SettingsRepository $settings
|
||||
*/
|
||||
public function __construct(SettingsRepository $settings)
|
||||
public function __construct(Dispatcher $events, SettingsRepository $settings)
|
||||
{
|
||||
$this->events = $events;
|
||||
$this->settings = $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param RegisterUser $command
|
||||
*
|
||||
* @throws PermissionDeniedException if signup is closed and the actor is
|
||||
* not an administrator.
|
||||
* @throws \Flarum\Core\Exceptions\InvalidConfirmationTokenException if an
|
||||
* @throws \Flarum\Core\Exception\InvalidConfirmationTokenException if an
|
||||
* email confirmation token is provided but is invalid.
|
||||
*
|
||||
* @return User
|
||||
*/
|
||||
public function handle(RegisterUser $command)
|
||||
@@ -50,8 +52,8 @@ class RegisterUserHandler
|
||||
$actor = $command->actor;
|
||||
$data = $command->data;
|
||||
|
||||
if (! $this->settings->get('allow_sign_up') && ! $actor->isAdmin()) {
|
||||
throw new PermissionDeniedException;
|
||||
if (! $this->settings->get('allow_sign_up')) {
|
||||
$this->assertAdmin($actor);
|
||||
}
|
||||
|
||||
$username = array_get($data, 'attributes.username');
|
||||
@@ -66,11 +68,7 @@ class RegisterUserHandler
|
||||
$password = $password ?: str_random(20);
|
||||
}
|
||||
|
||||
$user = User::register(
|
||||
$username,
|
||||
$email,
|
||||
$password
|
||||
);
|
||||
$user = User::register($username, $email, $password);
|
||||
|
||||
// If a valid authentication token was provided, then we will assign
|
||||
// the attributes associated with it to the user's account. If this
|
||||
@@ -86,7 +84,9 @@ class RegisterUserHandler
|
||||
}
|
||||
}
|
||||
|
||||
event(new UserWillBeSaved($user, $actor, $data));
|
||||
$this->events->fire(
|
||||
new UserWillBeSaved($user, $actor, $data)
|
||||
);
|
||||
|
||||
$user->save();
|
||||
|
||||
@@ -94,7 +94,7 @@ class RegisterUserHandler
|
||||
$token->delete();
|
||||
}
|
||||
|
||||
$this->dispatchEventsFor($user);
|
||||
$this->dispatchEventsFor($user, $actor);
|
||||
|
||||
return $user;
|
||||
}
|
@@ -8,7 +8,7 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Users\Commands;
|
||||
namespace Flarum\Core\Command;
|
||||
|
||||
class RequestPasswordReset
|
||||
{
|
@@ -8,11 +8,11 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Users\Commands;
|
||||
namespace Flarum\Core\Command;
|
||||
|
||||
use Flarum\Core\Settings\SettingsRepository;
|
||||
use Flarum\Core\Users\PasswordToken;
|
||||
use Flarum\Core\Users\UserRepository;
|
||||
use Flarum\Settings\SettingsRepository;
|
||||
use Flarum\Core\PasswordToken;
|
||||
use Flarum\Core\Repository\UserRepository;
|
||||
use Illuminate\Contracts\Mail\Mailer;
|
||||
use Illuminate\Mail\Message;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
@@ -57,7 +57,7 @@ class RequestPasswordResetHandler
|
||||
|
||||
/**
|
||||
* @param RequestPasswordReset $command
|
||||
* @return \Flarum\Core\Users\User
|
||||
* @return \Flarum\Core\User
|
||||
* @throws ModelNotFoundException
|
||||
*/
|
||||
public function handle(RequestPasswordReset $command)
|
||||
@@ -71,12 +71,9 @@ class RequestPasswordResetHandler
|
||||
$token = PasswordToken::generate($user->id);
|
||||
$token->save();
|
||||
|
||||
// TODO: Need to use UrlGenerator, but since this is part of core we
|
||||
// don't know that the forum routes will be loaded. Should the reset
|
||||
// password route be part of core??
|
||||
$data = [
|
||||
'username' => $user->username,
|
||||
'url' => Core::url().'/reset/'.$token->id,
|
||||
'url' => $this->url->toRoute('resetPassword', ['token' => $token->id]),
|
||||
'forumTitle' => $this->settings->get('forum_title'),
|
||||
];
|
||||
|
@@ -8,9 +8,9 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Discussions\Commands;
|
||||
namespace Flarum\Core\Command;
|
||||
|
||||
use Flarum\Core\Users\User;
|
||||
use Flarum\Core\User;
|
||||
|
||||
class StartDiscussion
|
||||
{
|
@@ -8,50 +8,48 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Discussions\Commands;
|
||||
namespace Flarum\Core\Command;
|
||||
|
||||
use Flarum\Events\DiscussionWillBeSaved;
|
||||
use Flarum\Core\Forum;
|
||||
use Illuminate\Contracts\Bus\Dispatcher;
|
||||
use Flarum\Core\Discussions\Discussion;
|
||||
use Flarum\Core\Posts\Commands\PostReply;
|
||||
use Flarum\Core\Support\DispatchesEvents;
|
||||
use Exception;
|
||||
use Flarum\Core\Access\AssertPermissionTrait;
|
||||
use Flarum\Core\Discussion;
|
||||
use Flarum\Core\Support\DispatchEventsTrait;
|
||||
use Flarum\Event\DiscussionWillBeSaved;
|
||||
use Illuminate\Contracts\Bus\Dispatcher as BusDispatcher;
|
||||
use Illuminate\Contracts\Events\Dispatcher as EventDispatcher;
|
||||
|
||||
class StartDiscussionHandler
|
||||
{
|
||||
use DispatchesEvents;
|
||||
use DispatchEventsTrait;
|
||||
use AssertPermissionTrait;
|
||||
|
||||
/**
|
||||
* @var Dispatcher
|
||||
* @var BusDispatcher
|
||||
*/
|
||||
protected $bus;
|
||||
|
||||
/**
|
||||
* @var Forum
|
||||
* @param EventDispatcher $events
|
||||
* @param BusDispatcher $bus
|
||||
* @internal param Forum $forum
|
||||
*/
|
||||
protected $forum;
|
||||
|
||||
/**
|
||||
* @param Dispatcher $bus
|
||||
* @param Forum $forum
|
||||
*/
|
||||
public function __construct(Dispatcher $bus, Forum $forum)
|
||||
public function __construct(EventDispatcher $events, BusDispatcher $bus)
|
||||
{
|
||||
$this->events = $events;
|
||||
$this->bus = $bus;
|
||||
$this->forum = $forum;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param StartDiscussion $command
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function handle(StartDiscussion $command)
|
||||
{
|
||||
$actor = $command->actor;
|
||||
$data = $command->data;
|
||||
|
||||
$this->forum->assertCan($actor, 'startDiscussion');
|
||||
$this->assertCan($actor, 'startDiscussion');
|
||||
|
||||
// Create a new Discussion entity, persist it, and dispatch domain
|
||||
// events. Before persistance, though, fire an event to give plugins
|
||||
@@ -62,7 +60,9 @@ class StartDiscussionHandler
|
||||
$actor
|
||||
);
|
||||
|
||||
event(new DiscussionWillBeSaved($discussion, $actor, $data));
|
||||
$this->events->fire(
|
||||
new DiscussionWillBeSaved($discussion, $actor, $data)
|
||||
);
|
||||
|
||||
$discussion->save();
|
||||
|
||||
@@ -84,7 +84,7 @@ class StartDiscussionHandler
|
||||
$discussion->setRawAttributes($post->discussion->getAttributes(), true);
|
||||
$discussion->setStartPost($post);
|
||||
|
||||
$this->dispatchEventsFor($discussion);
|
||||
$this->dispatchEventsFor($discussion, $actor);
|
||||
|
||||
$discussion->save();
|
||||
|
@@ -8,9 +8,9 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Users\Commands;
|
||||
namespace Flarum\Core\Command;
|
||||
|
||||
use Flarum\Core\Users\User;
|
||||
use Flarum\Core\User;
|
||||
use Psr\Http\Message\UploadedFileInterface;
|
||||
|
||||
class UploadAvatar
|
@@ -8,11 +8,13 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Users\Commands;
|
||||
namespace Flarum\Core\Command;
|
||||
|
||||
use Flarum\Events\AvatarWillBeSaved;
|
||||
use Flarum\Core\Users\UserRepository;
|
||||
use Flarum\Core\Support\DispatchesEvents;
|
||||
use Flarum\Core\Access\AssertPermissionTrait;
|
||||
use Flarum\Event\AvatarWillBeSaved;
|
||||
use Flarum\Core\Repository\UserRepository;
|
||||
use Flarum\Core\Support\DispatchEventsTrait;
|
||||
use Illuminate\Contracts\Events\Dispatcher;
|
||||
use Illuminate\Support\Str;
|
||||
use League\Flysystem\Adapter\Local;
|
||||
use League\Flysystem\Filesystem;
|
||||
@@ -22,7 +24,8 @@ use Intervention\Image\ImageManager;
|
||||
|
||||
class UploadAvatarHandler
|
||||
{
|
||||
use DispatchesEvents;
|
||||
use DispatchEventsTrait;
|
||||
use AssertPermissionTrait;
|
||||
|
||||
/**
|
||||
* @var UserRepository
|
||||
@@ -35,19 +38,21 @@ class UploadAvatarHandler
|
||||
protected $uploadDir;
|
||||
|
||||
/**
|
||||
* @param Dispatcher $events
|
||||
* @param UserRepository $users
|
||||
* @param FilesystemInterface $uploadDir
|
||||
*/
|
||||
public function __construct(UserRepository $users, FilesystemInterface $uploadDir)
|
||||
public function __construct(Dispatcher $events, UserRepository $users, FilesystemInterface $uploadDir)
|
||||
{
|
||||
$this->events = $events;
|
||||
$this->users = $users;
|
||||
$this->uploadDir = $uploadDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param UploadAvatar $command
|
||||
* @return \Flarum\Core\Users\User
|
||||
* @throws \Flarum\Core\Exceptions\PermissionDeniedException
|
||||
* @return \Flarum\Core\User
|
||||
* @throws \Flarum\Core\Exception\PermissionDeniedException
|
||||
*/
|
||||
public function handle(UploadAvatar $command)
|
||||
{
|
||||
@@ -55,20 +60,19 @@ class UploadAvatarHandler
|
||||
|
||||
$user = $this->users->findOrFail($command->userId);
|
||||
|
||||
// Make sure the current user is allowed to edit the user profile.
|
||||
// This will let admins and the user themselves pass through, and
|
||||
// throw an exception otherwise.
|
||||
if ($actor->id !== $user->id) {
|
||||
$user->assertCan($actor, 'edit');
|
||||
$this->assertCan($actor, 'edit', $user);
|
||||
}
|
||||
|
||||
$tmpFile = tempnam(sys_get_temp_dir(), 'avatar');
|
||||
$command->file->moveTo($tmpFile);
|
||||
|
||||
$manager = new ImageManager();
|
||||
$manager = new ImageManager;
|
||||
$manager->make($tmpFile)->fit(100, 100)->save();
|
||||
|
||||
event(new AvatarWillBeSaved($user, $actor, $tmpFile));
|
||||
$this->events->fire(
|
||||
new AvatarWillBeSaved($user, $actor, $tmpFile)
|
||||
);
|
||||
|
||||
$mount = new MountManager([
|
||||
'source' => new Filesystem(new Local(pathinfo($tmpFile, PATHINFO_DIRNAME))),
|
||||
@@ -86,7 +90,8 @@ class UploadAvatarHandler
|
||||
$mount->move("source://".pathinfo($tmpFile, PATHINFO_BASENAME), "target://$uploadName");
|
||||
|
||||
$user->save();
|
||||
$this->dispatchEventsFor($user);
|
||||
|
||||
$this->dispatchEventsFor($user, $actor);
|
||||
|
||||
return $user;
|
||||
}
|
@@ -10,17 +10,55 @@
|
||||
|
||||
namespace Flarum\Core;
|
||||
|
||||
use Flarum\Core\Users\User;
|
||||
use Flarum\Events\ModelAllow;
|
||||
use Flarum\Support\ServiceProvider;
|
||||
use Flarum\Extend;
|
||||
use Flarum\Core\Access\Gate;
|
||||
use Flarum\Core\Post\CommentPost;
|
||||
use Flarum\Event\ConfigurePostTypes;
|
||||
use Flarum\Event\ConfigureUserPreferences;
|
||||
use Flarum\Event\GetPermission;
|
||||
use Flarum\Foundation\AbstractServiceProvider;
|
||||
use Illuminate\Contracts\Container\Container;
|
||||
use RuntimeException;
|
||||
|
||||
class CoreServiceProvider extends ServiceProvider
|
||||
class CoreServiceProvider extends AbstractServiceProvider
|
||||
{
|
||||
/**
|
||||
* Bootstrap the application events.
|
||||
*
|
||||
* @return void
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
$this->app->singleton('flarum.gate', function ($app) {
|
||||
return new Gate($app, function () {
|
||||
throw new RuntimeException('You must set the gate user with forUser()');
|
||||
});
|
||||
});
|
||||
|
||||
$this->app->alias('flarum.gate', 'Illuminate\Contracts\Auth\Access\Gate');
|
||||
$this->app->alias('flarum.gate', 'Flarum\Core\Access\Gate');
|
||||
|
||||
$this->registerAvatarsFilesystem();
|
||||
|
||||
$this->app->register('Flarum\Core\Notification\NotificationServiceProvider');
|
||||
$this->app->register('Flarum\Core\Search\SearchServiceProvider');
|
||||
$this->app->register('Flarum\Formatter\FormatterServiceProvider');
|
||||
}
|
||||
|
||||
protected function registerAvatarsFilesystem()
|
||||
{
|
||||
$avatarsFilesystem = function (Container $app) {
|
||||
return $app->make('Illuminate\Contracts\Filesystem\Factory')->disk('flarum-avatars')->getDriver();
|
||||
};
|
||||
|
||||
$this->app->when('Flarum\Core\Command\UploadAvatarHandler')
|
||||
->needs('League\Flysystem\FilesystemInterface')
|
||||
->give($avatarsFilesystem);
|
||||
|
||||
$this->app->when('Flarum\Core\Command\DeleteAvatarHandler')
|
||||
->needs('League\Flysystem\FilesystemInterface')
|
||||
->give($avatarsFilesystem);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
@@ -30,32 +68,76 @@ class CoreServiceProvider extends ServiceProvider
|
||||
return get_class($command).'Handler@handle';
|
||||
});
|
||||
|
||||
$events = $this->app->make('events');
|
||||
|
||||
$events->listen(ModelAllow::class, function (ModelAllow $event) {
|
||||
if ($event->model instanceof Forum &&
|
||||
$event->actor->hasPermission('forum.'.$event->action)) {
|
||||
$this->app->make('flarum.gate')->before(function (User $actor, $ability, $model = null) {
|
||||
if ($actor->hasPermission($ability)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->app->make('events')->until(
|
||||
new GetPermission($actor, $ability, [$model])
|
||||
);
|
||||
});
|
||||
|
||||
$this->registerPostTypes();
|
||||
|
||||
CommentPost::setFormatter($this->app->make('flarum.formatter'));
|
||||
|
||||
User::setHasher($this->app->make('hash'));
|
||||
User::setGate($this->app->make('flarum.gate'));
|
||||
|
||||
$this->validateModelWith(User::class, 'Flarum\Core\Validator\UserValidator');
|
||||
$this->validateModelWith(Group::class, 'Flarum\Core\Validator\GroupValidator');
|
||||
$this->validateModelWith(Post::class, 'Flarum\Core\Validator\PostValidator');
|
||||
|
||||
$events = $this->app->make('events');
|
||||
|
||||
$events->subscribe('Flarum\Core\Listener\DiscussionMetadataUpdater');
|
||||
$events->subscribe('Flarum\Core\Listener\UserMetadataUpdater');
|
||||
$events->subscribe('Flarum\Core\Listener\EmailConfirmationMailer');
|
||||
$events->subscribe('Flarum\Core\Listener\DiscussionRenamedNotifier');
|
||||
|
||||
$events->subscribe('Flarum\Core\Access\DiscussionPolicy');
|
||||
$events->subscribe('Flarum\Core\Access\GroupPolicy');
|
||||
$events->subscribe('Flarum\Core\Access\PostPolicy');
|
||||
$events->subscribe('Flarum\Core\Access\UserPolicy');
|
||||
|
||||
$events->listen(ConfigureUserPreferences::class, [$this, 'configureUserPreferences']);
|
||||
}
|
||||
|
||||
public function registerPostTypes()
|
||||
{
|
||||
$models = [
|
||||
'Flarum\Core\Post\CommentPost',
|
||||
'Flarum\Core\Post\DiscussionRenamedPost'
|
||||
];
|
||||
|
||||
$this->app->make('events')->fire(
|
||||
new ConfigurePostTypes($models)
|
||||
);
|
||||
|
||||
foreach ($models as $model) {
|
||||
Post::setModel($model::$type, $model);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the service provider.
|
||||
*
|
||||
* @return void
|
||||
* @param ConfigureUserPreferences $event
|
||||
*/
|
||||
public function register()
|
||||
public function configureUserPreferences(ConfigureUserPreferences $event)
|
||||
{
|
||||
$this->app->singleton('flarum.forum', 'Flarum\Core\Forum');
|
||||
$event->add('discloseOnline', 'boolval', true);
|
||||
$event->add('indexProfile', 'boolval', true);
|
||||
$event->add('locale');
|
||||
}
|
||||
|
||||
// FIXME: probably use Illuminate's AggregateServiceProvider
|
||||
// functionality, because it includes the 'provides' stuff.
|
||||
$this->app->register('Flarum\Core\Discussions\DiscussionsServiceProvider');
|
||||
$this->app->register('Flarum\Core\Formatter\FormatterServiceProvider');
|
||||
$this->app->register('Flarum\Core\Groups\GroupsServiceProvider');
|
||||
$this->app->register('Flarum\Core\Notifications\NotificationsServiceProvider');
|
||||
$this->app->register('Flarum\Core\Posts\PostsServiceProvider');
|
||||
$this->app->register('Flarum\Core\Users\UsersServiceProvider');
|
||||
/**
|
||||
* @param string $model
|
||||
* @param string $validator
|
||||
*/
|
||||
protected function validateModelWith($model, $validator)
|
||||
{
|
||||
$model::saving(function ($model) use ($validator) {
|
||||
$this->app->make($validator)->assertValid($model);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@@ -1,64 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* (c) Toby Zerner <toby.zerner@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core;
|
||||
|
||||
use Flarum\Core;
|
||||
use Flarum\Support\ServiceProvider;
|
||||
use Illuminate\Database\ConnectionResolver;
|
||||
use Illuminate\Database\Connectors\ConnectionFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use PDO;
|
||||
use Flarum\Migrations\DatabaseMigrationRepository;
|
||||
|
||||
class DatabaseServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Register the service provider.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
$this->app->singleton('flarum.db', function () {
|
||||
$factory = new ConnectionFactory($this->app);
|
||||
$connection = $factory->make($this->app->make('flarum.config')['database']);
|
||||
$connection->setEventDispatcher($this->app->make('Illuminate\Contracts\Events\Dispatcher'));
|
||||
$connection->setFetchMode(PDO::FETCH_CLASS);
|
||||
return $connection;
|
||||
});
|
||||
|
||||
$this->app->alias('flarum.db', 'Illuminate\Database\ConnectionInterface');
|
||||
|
||||
$this->app->singleton('Illuminate\Database\ConnectionResolverInterface', function () {
|
||||
$resolver = new ConnectionResolver([
|
||||
'flarum' => $this->app->make('flarum.db'),
|
||||
]);
|
||||
$resolver->setDefaultConnection('flarum');
|
||||
return $resolver;
|
||||
});
|
||||
|
||||
$this->app->alias('Illuminate\Database\ConnectionResolverInterface', 'db');
|
||||
|
||||
if (Core::isInstalled()) {
|
||||
$this->app->booting(function () {
|
||||
$resolver = $this->app->make('Illuminate\Database\ConnectionResolverInterface');
|
||||
Model::setConnectionResolver($resolver);
|
||||
|
||||
Model::setEventDispatcher($this->app->make('events'));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
$this->app->singleton('Flarum\Migrations\MigrationRepositoryInterface', function ($app) {
|
||||
return new DatabaseMigrationRepository($app['db'], 'migrations');
|
||||
});
|
||||
}
|
||||
}
|
@@ -8,58 +8,56 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Discussions;
|
||||
namespace Flarum\Core;
|
||||
|
||||
use Flarum\Core\Model;
|
||||
use Flarum\Events\DiscussionWasDeleted;
|
||||
use Flarum\Events\DiscussionWasStarted;
|
||||
use Flarum\Events\DiscussionWasRenamed;
|
||||
use Flarum\Events\DiscussionWasHidden;
|
||||
use Flarum\Events\DiscussionWasRestored;
|
||||
use Flarum\Events\PostWasDeleted;
|
||||
use Flarum\Events\ScopePostVisibility;
|
||||
use Flarum\Core\Posts\Post;
|
||||
use Flarum\Core\Posts\MergeablePost;
|
||||
use Flarum\Core\Users\Guest;
|
||||
use Flarum\Core\Users\User;
|
||||
use Flarum\Core\Support\EventGenerator;
|
||||
use Flarum\Core\Support\Locked;
|
||||
use Flarum\Core\Support\VisibleScope;
|
||||
use Flarum\Core\Support\ValidatesBeforeSave;
|
||||
use Flarum\Core\Post;
|
||||
use Flarum\Core\Post\MergeableInterface;
|
||||
use Flarum\Core\Support\EventGeneratorTrait;
|
||||
use Flarum\Core\Support\ScopeVisibilityTrait;
|
||||
use Flarum\Database\AbstractModel;
|
||||
use Flarum\Event\DiscussionWasDeleted;
|
||||
use Flarum\Event\DiscussionWasHidden;
|
||||
use Flarum\Event\DiscussionWasRenamed;
|
||||
use Flarum\Event\DiscussionWasRestored;
|
||||
use Flarum\Event\DiscussionWasStarted;
|
||||
use Flarum\Event\PostWasDeleted;
|
||||
use Flarum\Event\ScopePostVisibility;
|
||||
|
||||
/**
|
||||
* @todo document database columns with @property
|
||||
* @property int $id
|
||||
* @property string $title
|
||||
* @property int $comments_count
|
||||
* @property int $participants_count
|
||||
* @property int $number_index
|
||||
* @property \Carbon\Carbon $start_time
|
||||
* @property int|null $start_user_id
|
||||
* @property int|null $start_post_id
|
||||
* @property \Carbon\Carbon|null $last_time
|
||||
* @property int|null $last_user_id
|
||||
* @property int|null $last_post_id
|
||||
* @property int|null $last_post_number
|
||||
* @property \Carbon\Carbon|null $hide_time
|
||||
* @property int|null $hide_user_id
|
||||
* @property DiscussionState|null $state
|
||||
* @property \Illuminate\Database\Eloquent\Collection $posts
|
||||
* @property \Illuminate\Database\Eloquent\Collection $comments
|
||||
* @property \Illuminate\Database\Eloquent\Collection $participants
|
||||
* @property Post|null $startPost
|
||||
* @property User|null $startUser
|
||||
* @property Post|null $lastPost
|
||||
* @property User|null $lastUser
|
||||
* @property \Illuminate\Database\Eloquent\Collection $readers
|
||||
*/
|
||||
class Discussion extends Model
|
||||
class Discussion extends AbstractModel
|
||||
{
|
||||
use EventGenerator;
|
||||
use Locked;
|
||||
use VisibleScope;
|
||||
use ValidatesBeforeSave;
|
||||
use EventGeneratorTrait;
|
||||
use ScopeVisibilityTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $table = 'discussions';
|
||||
|
||||
/**
|
||||
* The validation rules for this model.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $rules = [
|
||||
'title' => 'required|max:80',
|
||||
'start_time' => 'required|date',
|
||||
'comments_count' => 'integer',
|
||||
'participants_count' => 'integer',
|
||||
'start_user_id' => 'integer',
|
||||
'start_post_id' => 'integer',
|
||||
'last_time' => 'date',
|
||||
'last_user_id' => 'integer',
|
||||
'last_post_id' => 'integer',
|
||||
'last_post_number' => 'integer'
|
||||
];
|
||||
|
||||
/**
|
||||
* An array of posts that have been modified during this request.
|
||||
*
|
||||
@@ -134,16 +132,15 @@ class Discussion extends Model
|
||||
* Rename the discussion. Raises the DiscussionWasRenamed event.
|
||||
*
|
||||
* @param string $title
|
||||
* @param User $user
|
||||
* @return $this
|
||||
*/
|
||||
public function rename($title, User $user)
|
||||
public function rename($title)
|
||||
{
|
||||
if ($this->title !== $title) {
|
||||
$oldTitle = $this->title;
|
||||
$this->title = $title;
|
||||
|
||||
$this->raise(new DiscussionWasRenamed($this, $user, $oldTitle));
|
||||
$this->raise(new DiscussionWasRenamed($this, $oldTitle));
|
||||
}
|
||||
|
||||
return $this;
|
||||
@@ -261,12 +258,12 @@ class Discussion extends Model
|
||||
* DiscussionRenamedPost, and delete if the title has been reverted
|
||||
* completely.)
|
||||
*
|
||||
* @param MergeablePost $post The post to save.
|
||||
* @param MergeableInterface $post The post to save.
|
||||
* @return Post The resulting post. It may or may not be the same post as
|
||||
* was originally intended to be saved. It also may not exist, if the
|
||||
* merge logic resulted in deletion.
|
||||
*/
|
||||
public function mergePost(MergeablePost $post)
|
||||
public function mergePost(MergeableInterface $post)
|
||||
{
|
||||
$lastPost = $this->posts()->latest('time')->first();
|
||||
|
||||
@@ -292,7 +289,7 @@ class Discussion extends Model
|
||||
*/
|
||||
public function posts()
|
||||
{
|
||||
return $this->hasMany('Flarum\Core\Posts\Post');
|
||||
return $this->hasMany('Flarum\Core\Post');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -304,11 +301,13 @@ class Discussion extends Model
|
||||
*/
|
||||
public function postsVisibleTo(User $user)
|
||||
{
|
||||
$query = $this->posts()->getQuery();
|
||||
$relation = $this->posts();
|
||||
|
||||
event(new ScopePostVisibility($this, $query, $user));
|
||||
static::$dispatcher->fire(
|
||||
new ScopePostVisibility($this, $relation->getQuery(), $user)
|
||||
);
|
||||
|
||||
return $query;
|
||||
return $relation;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -342,7 +341,7 @@ class Discussion extends Model
|
||||
*/
|
||||
public function startPost()
|
||||
{
|
||||
return $this->belongsTo('Flarum\Core\Posts\Post', 'start_post_id');
|
||||
return $this->belongsTo('Flarum\Core\Post', 'start_post_id');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -352,7 +351,7 @@ class Discussion extends Model
|
||||
*/
|
||||
public function startUser()
|
||||
{
|
||||
return $this->belongsTo('Flarum\Core\Users\User', 'start_user_id');
|
||||
return $this->belongsTo('Flarum\Core\User', 'start_user_id');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -362,7 +361,7 @@ class Discussion extends Model
|
||||
*/
|
||||
public function lastPost()
|
||||
{
|
||||
return $this->belongsTo('Flarum\Core\Posts\Post', 'last_post_id');
|
||||
return $this->belongsTo('Flarum\Core\Post', 'last_post_id');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -372,7 +371,7 @@ class Discussion extends Model
|
||||
*/
|
||||
public function lastUser()
|
||||
{
|
||||
return $this->belongsTo('Flarum\Core\Users\User', 'last_user_id');
|
||||
return $this->belongsTo('Flarum\Core\User', 'last_user_id');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -382,7 +381,7 @@ class Discussion extends Model
|
||||
*/
|
||||
public function readers()
|
||||
{
|
||||
return $this->belongsToMany('Flarum\Core\Users\User', 'users_discussions');
|
||||
return $this->belongsToMany('Flarum\Core\User', 'users_discussions');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -401,7 +400,7 @@ class Discussion extends Model
|
||||
{
|
||||
$user = $user ?: static::$stateUser;
|
||||
|
||||
return $this->hasOne('Flarum\Core\Discussions\DiscussionState')->where('user_id', $user ? $user->id : null);
|
||||
return $this->hasOne('Flarum\Core\DiscussionState')->where('user_id', $user ? $user->id : null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -409,7 +408,7 @@ class Discussion extends Model
|
||||
* exist.
|
||||
*
|
||||
* @param User $user
|
||||
* @return \Flarum\Core\Discussions\DiscussionState
|
||||
* @return \Flarum\Core\DiscussionState
|
||||
*/
|
||||
public function stateFor(User $user)
|
||||
{
|
@@ -8,11 +8,11 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Discussions;
|
||||
namespace Flarum\Core;
|
||||
|
||||
use Flarum\Events\DiscussionWasRead;
|
||||
use Flarum\Core\Model;
|
||||
use Flarum\Core\Support\EventGenerator;
|
||||
use Flarum\Event\DiscussionWasRead;
|
||||
use Flarum\Database\AbstractModel;
|
||||
use Flarum\Core\Support\EventGeneratorTrait;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
/**
|
||||
@@ -22,11 +22,16 @@ use Illuminate\Database\Eloquent\Builder;
|
||||
* be used to store other information, if the appropriate columns are added to
|
||||
* the database, like a user's subscription status for a discussion.
|
||||
*
|
||||
* @todo document database columns with @property
|
||||
* @property int $user_id
|
||||
* @property int $discussion_id
|
||||
* @property \Carbon\Carbon|null $read_time
|
||||
* @property int|null $read_number
|
||||
* @property Discussion $discussion
|
||||
* @property \Flarum\Core\User $user
|
||||
*/
|
||||
class DiscussionState extends Model
|
||||
class DiscussionState extends AbstractModel
|
||||
{
|
||||
use EventGenerator;
|
||||
use EventGeneratorTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
@@ -64,7 +69,7 @@ class DiscussionState extends Model
|
||||
*/
|
||||
public function discussion()
|
||||
{
|
||||
return $this->belongsTo('Flarum\Core\Discussions\Discussion', 'discussion_id');
|
||||
return $this->belongsTo('Flarum\Core\Discussion', 'discussion_id');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,7 +79,7 @@ class DiscussionState extends Model
|
||||
*/
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo('Flarum\Core\Users\User', 'user_id');
|
||||
return $this->belongsTo('Flarum\Core\User', 'user_id');
|
||||
}
|
||||
|
||||
/**
|
@@ -1,54 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* (c) Toby Zerner <toby.zerner@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Discussions\Commands;
|
||||
|
||||
use Flarum\Core\Discussions\DiscussionRepository;
|
||||
use Flarum\Events\DiscussionWillBeDeleted;
|
||||
use Flarum\Core\Support\DispatchesEvents;
|
||||
|
||||
class DeleteDiscussionHandler
|
||||
{
|
||||
use DispatchesEvents;
|
||||
|
||||
/**
|
||||
* @var \Flarum\Core\Discussions\DiscussionRepository
|
||||
*/
|
||||
protected $discussions;
|
||||
|
||||
/**
|
||||
* @param \Flarum\Core\Discussions\DiscussionRepository $discussions
|
||||
*/
|
||||
public function __construct(DiscussionRepository $discussions)
|
||||
{
|
||||
$this->discussions = $discussions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Flarum\Core\Discussions\Commands\DeleteDiscussion $command
|
||||
* @return \Flarum\Core\Discussions\Discussion
|
||||
*/
|
||||
public function handle(DeleteDiscussion $command)
|
||||
{
|
||||
$actor = $command->actor;
|
||||
|
||||
$discussion = $this->discussions->findOrFail($command->discussionId, $actor);
|
||||
|
||||
$discussion->assertCan($actor, 'delete');
|
||||
|
||||
event(new DiscussionWillBeDeleted($discussion, $actor, $command->data));
|
||||
|
||||
$discussion->delete();
|
||||
|
||||
$this->dispatchEventsFor($discussion);
|
||||
|
||||
return $discussion;
|
||||
}
|
||||
}
|
@@ -1,103 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* (c) Toby Zerner <toby.zerner@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Discussions;
|
||||
|
||||
use Flarum\Core\Search\GambitManager;
|
||||
use Flarum\Core\Users\User;
|
||||
use Flarum\Events\ModelAllow;
|
||||
use Flarum\Events\ScopeModelVisibility;
|
||||
use Flarum\Events\RegisterDiscussionGambits;
|
||||
use Flarum\Events\ScopeHiddenDiscussionVisibility;
|
||||
use Flarum\Support\ServiceProvider;
|
||||
use Flarum\Extend;
|
||||
use Illuminate\Contracts\Container\Container;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class DiscussionsServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Bootstrap the application events.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
Discussion::setValidator($this->app->make('validator'));
|
||||
|
||||
$events = $this->app->make('events');
|
||||
$settings = $this->app->make('Flarum\Core\Settings\SettingsRepository');
|
||||
|
||||
$events->subscribe('Flarum\Core\Discussions\Listeners\DiscussionMetadataUpdater');
|
||||
|
||||
$events->listen(ModelAllow::class, function (ModelAllow $event) use ($settings) {
|
||||
if ($event->model instanceof Discussion) {
|
||||
if ($event->actor->hasPermission('discussion.'.$event->action)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (($event->action === 'rename' || $event->action === 'delete') &&
|
||||
$event->model->start_user_id == $event->actor->id) {
|
||||
$allowRenaming = $settings->get('allow_renaming');
|
||||
|
||||
if ($allowRenaming === '-1' ||
|
||||
($allowRenaming === 'reply' && $event->model->participants_count <= 1) ||
|
||||
($event->model->start_time->diffInMinutes(Carbon::now()) < $allowRenaming)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$events->listen(ScopeModelVisibility::class, function (ScopeModelVisibility $event) {
|
||||
if ($event->model instanceof Discussion) {
|
||||
$user = $event->actor;
|
||||
|
||||
if (! $user->hasPermission('discussion.hide')) {
|
||||
$event->query->where(function ($query) use ($user) {
|
||||
$query->whereNull('discussions.hide_time')
|
||||
->where('comments_count', '>', 0)
|
||||
->orWhere('start_user_id', $user->id);
|
||||
|
||||
event(new ScopeHiddenDiscussionVisibility($query, $user, 'discussion.hide'));
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the service provider.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
$this->app->bind(
|
||||
'Flarum\Core\Discussions\Search\Fulltext\Driver',
|
||||
'Flarum\Core\Discussions\Search\Fulltext\MySqlFulltextDriver'
|
||||
);
|
||||
|
||||
$this->app->when('Flarum\Core\Discussions\Search\DiscussionSearcher')
|
||||
->needs('Flarum\Core\Search\GambitManager')
|
||||
->give(function (Container $app) {
|
||||
$gambits = new GambitManager($app);
|
||||
|
||||
$gambits->setFulltextGambit('Flarum\Core\Discussions\Search\Gambits\FulltextGambit');
|
||||
$gambits->add('Flarum\Core\Discussions\Search\Gambits\AuthorGambit');
|
||||
$gambits->add('Flarum\Core\Discussions\Search\Gambits\HiddenGambit');
|
||||
$gambits->add('Flarum\Core\Discussions\Search\Gambits\UnreadGambit');
|
||||
|
||||
event(new RegisterDiscussionGambits($gambits));
|
||||
|
||||
return $gambits;
|
||||
});
|
||||
}
|
||||
}
|
@@ -8,16 +8,16 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Users;
|
||||
namespace Flarum\Core;
|
||||
|
||||
use Flarum\Core\Model;
|
||||
use Flarum\Core\Exceptions\InvalidConfirmationTokenException;
|
||||
use Flarum\Database\AbstractModel;
|
||||
use Flarum\Core\Exception\InvalidConfirmationTokenException;
|
||||
use DateTime;
|
||||
|
||||
/**
|
||||
* @todo document database columns with @property
|
||||
*/
|
||||
class EmailToken extends Model
|
||||
class EmailToken extends AbstractModel
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
@@ -63,7 +63,7 @@ class EmailToken extends Model
|
||||
*/
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo('Flarum\Core\Users\User');
|
||||
return $this->belongsTo('Flarum\Core\User');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -71,10 +71,8 @@ class EmailToken extends Model
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @param string $id
|
||||
*
|
||||
* @throws InvalidConfirmationTokenException
|
||||
*
|
||||
* @return static
|
||||
* @throws InvalidConfirmationTokenException
|
||||
*/
|
||||
public function scopeValidOrFail($query, $id)
|
||||
{
|
@@ -8,11 +8,12 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Exceptions;
|
||||
namespace Flarum\Core\Exception;
|
||||
|
||||
use Exception;
|
||||
use Tobscure\JsonApi\Exception\JsonApiSerializableInterface;
|
||||
|
||||
class InvalidConfirmationTokenException extends Exception implements JsonApiSerializable
|
||||
class InvalidConfirmationTokenException extends Exception implements JsonApiSerializableInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
@@ -8,11 +8,12 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Exceptions;
|
||||
namespace Flarum\Core\Exception;
|
||||
|
||||
use Exception;
|
||||
use Tobscure\JsonApi\Exception\JsonApiSerializableInterface;
|
||||
|
||||
class PermissionDeniedException extends Exception implements JsonApiSerializable
|
||||
class PermissionDeniedException extends Exception implements JsonApiSerializableInterface
|
||||
{
|
||||
/**
|
||||
* Return the HTTP status code to be used for this exception.
|
@@ -8,11 +8,12 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Exceptions;
|
||||
namespace Flarum\Core\Exception;
|
||||
|
||||
use Exception;
|
||||
use Tobscure\JsonApi\Exception\JsonApiSerializableInterface;
|
||||
|
||||
class ValidationException extends Exception implements JsonApiSerializable
|
||||
class ValidationException extends Exception implements JsonApiSerializableInterface
|
||||
{
|
||||
protected $messages;
|
||||
|
@@ -1,29 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* (c) Toby Zerner <toby.zerner@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Exceptions;
|
||||
|
||||
interface JsonApiSerializable
|
||||
{
|
||||
/**
|
||||
* Return the HTTP status code to be used for this exception.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getStatusCode();
|
||||
|
||||
/**
|
||||
* Return an array of errors, formatted as JSON-API error objects.
|
||||
*
|
||||
* @see http://jsonapi.org/format/#error-objects
|
||||
* @return array
|
||||
*/
|
||||
public function getErrors();
|
||||
}
|
@@ -1,131 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* (c) Toby Zerner <toby.zerner@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Formatter;
|
||||
|
||||
use Illuminate\Contracts\Cache\Repository;
|
||||
use s9e\TextFormatter\Configurator;
|
||||
use s9e\TextFormatter\Unparser;
|
||||
use Flarum\Events\FormatterConfigurator;
|
||||
use Flarum\Events\FormatterParser;
|
||||
use Flarum\Events\FormatterRenderer;
|
||||
use Flarum\Core\Posts\CommentPost;
|
||||
|
||||
class Formatter
|
||||
{
|
||||
protected $cache;
|
||||
|
||||
public function __construct(Repository $cache)
|
||||
{
|
||||
$this->cache = $cache;
|
||||
}
|
||||
|
||||
protected function getConfigurator()
|
||||
{
|
||||
$configurator = new Configurator;
|
||||
$configurator->rootRules->enableAutoLineBreaks();
|
||||
|
||||
$configurator->rendering->engine = 'PHP';
|
||||
$configurator->rendering->engine->cacheDir = storage_path() . '/app';
|
||||
|
||||
$configurator->Escaper;
|
||||
$configurator->Autoemail;
|
||||
$configurator->Autolink;
|
||||
$configurator->tags->onDuplicate('replace');
|
||||
|
||||
event(new FormatterConfigurator($configurator));
|
||||
|
||||
$dom = $configurator->tags['URL']->template->asDOM();
|
||||
|
||||
foreach ($dom->getElementsByTagName('a') as $a) {
|
||||
$a->setAttribute('target', '_blank');
|
||||
$a->setAttribute('rel', 'nofollow');
|
||||
}
|
||||
|
||||
$dom->saveChanges();
|
||||
|
||||
return $configurator;
|
||||
}
|
||||
|
||||
public function flush()
|
||||
{
|
||||
$this->cache->forget('flarum.formatter.parser');
|
||||
$this->cache->forget('flarum.formatter.renderer');
|
||||
}
|
||||
|
||||
protected function getComponent($key)
|
||||
{
|
||||
$cacheKey = 'flarum.formatter.' . $key;
|
||||
|
||||
return $this->cache->rememberForever($cacheKey, function () use ($key) {
|
||||
return $this->getConfigurator()->finalize()[$key];
|
||||
});
|
||||
}
|
||||
|
||||
protected function getParser($context = null)
|
||||
{
|
||||
$parser = $this->getComponent('parser');
|
||||
|
||||
$parser->registeredVars['context'] = $context;
|
||||
|
||||
event(new FormatterParser($parser, $context));
|
||||
|
||||
return $parser;
|
||||
}
|
||||
|
||||
protected function getRenderer($context = null)
|
||||
{
|
||||
spl_autoload_register(function ($class) {
|
||||
if (file_exists($file = storage_path() . '/app/' . $class . '.php')) {
|
||||
include $file;
|
||||
}
|
||||
});
|
||||
|
||||
$renderer = $this->getComponent('renderer');
|
||||
|
||||
event(new FormatterRenderer($renderer, $context));
|
||||
|
||||
return $renderer;
|
||||
}
|
||||
|
||||
public function getJS()
|
||||
{
|
||||
$configurator = $this->getConfigurator();
|
||||
$configurator->enableJavaScript();
|
||||
$configurator->javascript->exportMethods = ['preview'];
|
||||
$minifier = $configurator->javascript->setMinifier('ClosureCompilerService');
|
||||
$minifier->keepGoing = true;
|
||||
$minifier->cacheDir = storage_path() . '/app';
|
||||
|
||||
return $configurator->finalize([
|
||||
'returnParser' => false,
|
||||
'returnRenderer' => false
|
||||
])['js'];
|
||||
}
|
||||
|
||||
public function parse($text, $context = null)
|
||||
{
|
||||
$parser = $this->getParser($context);
|
||||
|
||||
return $parser->parse($text);
|
||||
}
|
||||
|
||||
public function render($xml, $context = null)
|
||||
{
|
||||
$renderer = $this->getRenderer($context);
|
||||
|
||||
return $renderer->render($xml);
|
||||
}
|
||||
|
||||
public function unparse($xml)
|
||||
{
|
||||
return Unparser::unparse($xml);
|
||||
}
|
||||
}
|
@@ -1,36 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* (c) Toby Zerner <toby.zerner@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Formatter;
|
||||
|
||||
use Flarum\Support\ServiceProvider;
|
||||
use Flarum\Extend;
|
||||
|
||||
class FormatterServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Bootstrap the application events.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the service provider.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
$this->app->singleton('flarum.formatter', 'Flarum\Core\Formatter\Formatter');
|
||||
}
|
||||
}
|
@@ -1,24 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* (c) Toby Zerner <toby.zerner@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core;
|
||||
|
||||
use Flarum\Core\Support\Locked;
|
||||
use Flarum\Core;
|
||||
|
||||
class Forum extends Model
|
||||
{
|
||||
use Locked;
|
||||
|
||||
public function getTitleAttribute()
|
||||
{
|
||||
return Core::config('forum_title');
|
||||
}
|
||||
}
|
@@ -8,42 +8,35 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Groups;
|
||||
namespace Flarum\Core;
|
||||
|
||||
use Flarum\Core\Model;
|
||||
use Flarum\Core\Support\EventGeneratorTrait;
|
||||
use Flarum\Core\Support\Locked;
|
||||
use Flarum\Core\Support\VisibleScope;
|
||||
use Flarum\Core\Support\EventGenerator;
|
||||
use Flarum\Core\Support\ValidatesBeforeSave;
|
||||
use Flarum\Events\GroupWasDeleted;
|
||||
use Flarum\Events\GroupWasCreated;
|
||||
use Flarum\Events\GroupWasRenamed;
|
||||
use Flarum\Core\Support\ScopeVisibilityTrait;
|
||||
use Flarum\Database\AbstractModel;
|
||||
use Flarum\Event\GroupWasCreated;
|
||||
use Flarum\Event\GroupWasDeleted;
|
||||
use Flarum\Event\GroupWasRenamed;
|
||||
|
||||
/**
|
||||
* @todo document database columns with @property
|
||||
* @property int $id
|
||||
* @property string $name_singular
|
||||
* @property string $name_plural
|
||||
* @property string|null $color
|
||||
* @property string|null $icon
|
||||
* @property \Illuminate\Database\Eloquent\Collection $users
|
||||
* @property \Illuminate\Database\Eloquent\Collection $permissions
|
||||
*/
|
||||
class Group extends Model
|
||||
class Group extends AbstractModel
|
||||
{
|
||||
use ValidatesBeforeSave;
|
||||
use EventGenerator;
|
||||
use Locked;
|
||||
use VisibleScope;
|
||||
use EventGeneratorTrait;
|
||||
use ScopeVisibilityTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $table = 'groups';
|
||||
|
||||
/**
|
||||
* The validation rules for this model.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $rules = [
|
||||
'name_singular' => 'required',
|
||||
'name_plural' => 'required'
|
||||
];
|
||||
|
||||
/**
|
||||
* The ID of the administrator group.
|
||||
*/
|
||||
@@ -68,7 +61,7 @@ class Group extends Model
|
||||
{
|
||||
parent::boot();
|
||||
|
||||
static::deleted(function ($group) {
|
||||
static::deleted(function (Group $group) {
|
||||
$group->raise(new GroupWasDeleted($group));
|
||||
|
||||
$group->permissions()->delete();
|
||||
@@ -110,6 +103,8 @@ class Group extends Model
|
||||
$this->name_singular = $nameSingular;
|
||||
$this->name_plural = $namePlural;
|
||||
|
||||
$this->raise(new GroupWasRenamed($this));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -120,7 +115,7 @@ class Group extends Model
|
||||
*/
|
||||
public function users()
|
||||
{
|
||||
return $this->belongsToMany('Flarum\Core\Users\User', 'users_groups');
|
||||
return $this->belongsToMany('Flarum\Core\User', 'users_groups');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -130,6 +125,6 @@ class Group extends Model
|
||||
*/
|
||||
public function permissions()
|
||||
{
|
||||
return $this->hasMany('Flarum\Core\Groups\Permission');
|
||||
return $this->hasMany('Flarum\Core\Permission');
|
||||
}
|
||||
}
|
@@ -1,55 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* (c) Toby Zerner <toby.zerner@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Groups\Commands;
|
||||
|
||||
use Flarum\Core\Groups\Group;
|
||||
use Flarum\Core\Groups\GroupRepository;
|
||||
use Flarum\Events\GroupWillBeDeleted;
|
||||
use Flarum\Core\Support\DispatchesEvents;
|
||||
|
||||
class DeleteGroupHandler
|
||||
{
|
||||
use DispatchesEvents;
|
||||
|
||||
/**
|
||||
* @var GroupRepository
|
||||
*/
|
||||
protected $groups;
|
||||
|
||||
/**
|
||||
* @param GroupRepository $groups
|
||||
*/
|
||||
public function __construct(GroupRepository $groups)
|
||||
{
|
||||
$this->groups = $groups;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DeleteGroup $command
|
||||
* @return Group
|
||||
* @throws \Flarum\Core\Exceptions\PermissionDeniedException
|
||||
*/
|
||||
public function handle(DeleteGroup $command)
|
||||
{
|
||||
$actor = $command->actor;
|
||||
|
||||
$group = $this->groups->findOrFail($command->groupId, $actor);
|
||||
|
||||
$group->assertCan($actor, 'delete');
|
||||
|
||||
event(new GroupWillBeDeleted($group, $actor, $command->data));
|
||||
|
||||
$group->delete();
|
||||
$this->dispatchEventsFor($group);
|
||||
|
||||
return $group;
|
||||
}
|
||||
}
|
@@ -1,38 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* (c) Toby Zerner <toby.zerner@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Groups;
|
||||
|
||||
use Flarum\Events\ModelAllow;
|
||||
use Flarum\Support\ServiceProvider;
|
||||
use Illuminate\Contracts\Container\Container;
|
||||
|
||||
class GroupsServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Bootstrap the application events.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
Group::setValidator($this->app->make('validator'));
|
||||
|
||||
$events = $this->app->make('events');
|
||||
|
||||
$events->listen(ModelAllow::class, function (ModelAllow $event) {
|
||||
if ($event->model instanceof Group) {
|
||||
if ($event->actor->hasPermission('group.'.$event->action)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@@ -8,9 +8,9 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Users;
|
||||
namespace Flarum\Core;
|
||||
|
||||
use Flarum\Core\Groups\Group;
|
||||
use Flarum\Core\Group;
|
||||
|
||||
class Guest extends User
|
||||
{
|
@@ -8,13 +8,13 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Discussions\Listeners;
|
||||
namespace Flarum\Core\Listener;
|
||||
|
||||
use Flarum\Core\Posts\Post;
|
||||
use Flarum\Events\PostWasPosted;
|
||||
use Flarum\Events\PostWasDeleted;
|
||||
use Flarum\Events\PostWasHidden;
|
||||
use Flarum\Events\PostWasRestored;
|
||||
use Flarum\Core\Post;
|
||||
use Flarum\Event\PostWasPosted;
|
||||
use Flarum\Event\PostWasDeleted;
|
||||
use Flarum\Event\PostWasHidden;
|
||||
use Flarum\Event\PostWasRestored;
|
||||
use Illuminate\Contracts\Events\Dispatcher;
|
||||
|
||||
class DiscussionMetadataUpdater
|
||||
@@ -46,7 +46,7 @@ class DiscussionMetadataUpdater
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Flarum\Events\PostWasDeleted $event
|
||||
* @param \Flarum\Event\PostWasDeleted $event
|
||||
*/
|
||||
public function whenPostWasDeleted(PostWasDeleted $event)
|
||||
{
|
@@ -8,12 +8,12 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Notifications\Listeners;
|
||||
namespace Flarum\Core\Listener;
|
||||
|
||||
use Flarum\Events\DiscussionWasRenamed;
|
||||
use Flarum\Core\Posts\DiscussionRenamedPost;
|
||||
use Flarum\Core\Notifications\DiscussionRenamedBlueprint;
|
||||
use Flarum\Core\Notifications\NotificationSyncer;
|
||||
use Flarum\Event\DiscussionWasRenamed;
|
||||
use Flarum\Core\Post\DiscussionRenamedPost;
|
||||
use Flarum\Core\Notification\DiscussionRenamedBlueprint;
|
||||
use Flarum\Core\Notification\NotificationSyncer;
|
||||
use Illuminate\Contracts\Events\Dispatcher;
|
||||
|
||||
class DiscussionRenamedNotifier
|
||||
@@ -40,7 +40,7 @@ class DiscussionRenamedNotifier
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Flarum\Events\DiscussionWasRenamed $event
|
||||
* @param \Flarum\Event\DiscussionWasRenamed $event
|
||||
*/
|
||||
public function whenDiscussionWasRenamed(DiscussionWasRenamed $event)
|
||||
{
|
@@ -8,14 +8,15 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Users\Listeners;
|
||||
namespace Flarum\Core\Listener;
|
||||
|
||||
use Flarum\Core\Settings\SettingsRepository;
|
||||
use Flarum\Events\UserWasRegistered;
|
||||
use Flarum\Events\UserEmailChangeWasRequested;
|
||||
use Flarum\Core;
|
||||
use Flarum\Core\Users\EmailToken;
|
||||
use Flarum\Core\Users\User;
|
||||
use Flarum\Core\EmailToken;
|
||||
use Flarum\Core\User;
|
||||
use Flarum\Event\UserEmailChangeWasRequested;
|
||||
use Flarum\Event\UserWasRegistered;
|
||||
use Flarum\Forum\UrlGenerator;
|
||||
use Flarum\Settings\SettingsRepository;
|
||||
use Illuminate\Contracts\Events\Dispatcher;
|
||||
use Illuminate\Contracts\Mail\Mailer;
|
||||
use Illuminate\Mail\Message;
|
||||
@@ -31,15 +32,21 @@ class EmailConfirmationMailer
|
||||
* @var Mailer
|
||||
*/
|
||||
protected $mailer;
|
||||
/**
|
||||
* @var UrlGenerator
|
||||
*/
|
||||
private $url;
|
||||
|
||||
/**
|
||||
* @param SettingsRepository $settings
|
||||
* @param \Flarum\Settings\SettingsRepository $settings
|
||||
* @param Mailer $mailer
|
||||
* @param UrlGenerator $url
|
||||
*/
|
||||
public function __construct(SettingsRepository $settings, Mailer $mailer)
|
||||
public function __construct(SettingsRepository $settings, Mailer $mailer, UrlGenerator $url)
|
||||
{
|
||||
$this->settings = $settings;
|
||||
$this->mailer = $mailer;
|
||||
$this->url = $url;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -52,7 +59,7 @@ class EmailConfirmationMailer
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Flarum\Events\UserWasRegistered $event
|
||||
* @param \Flarum\Event\UserWasRegistered $event
|
||||
*/
|
||||
public function whenUserWasRegistered(UserWasRegistered $event)
|
||||
{
|
||||
@@ -71,7 +78,7 @@ class EmailConfirmationMailer
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Flarum\Events\UserEmailChangeWasRequested $event
|
||||
* @param \Flarum\Event\UserEmailChangeWasRequested $event
|
||||
*/
|
||||
public function whenUserEmailChangeWasRequested(UserEmailChangeWasRequested $event)
|
||||
{
|
||||
@@ -110,12 +117,12 @@ class EmailConfirmationMailer
|
||||
{
|
||||
$token = $this->generateToken($user, $email);
|
||||
|
||||
// TODO: Need to use UrlGenerator, but since this is part of core we
|
||||
// TODO: Need to use AbstractUrlGenerator, but since this is part of core we
|
||||
// don't know that the forum routes will be loaded. Should the confirm
|
||||
// email route be part of core??
|
||||
return [
|
||||
'username' => $user->username,
|
||||
'url' => Core::url().'/confirm/'.$token->id,
|
||||
'url' => $this->url->toRoute('confirmEmail', ['token' => $token->id]),
|
||||
'forumTitle' => $this->settings->get('forum_title')
|
||||
];
|
||||
}
|
@@ -8,16 +8,16 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Users\Listeners;
|
||||
namespace Flarum\Core\Listener;
|
||||
|
||||
use Flarum\Core\Posts\Post;
|
||||
use Flarum\Core\Discussions\Discussion;
|
||||
use Flarum\Events\PostWasPosted;
|
||||
use Flarum\Events\PostWasDeleted;
|
||||
use Flarum\Events\PostWasHidden;
|
||||
use Flarum\Events\PostWasRestored;
|
||||
use Flarum\Events\DiscussionWasStarted;
|
||||
use Flarum\Events\DiscussionWasDeleted;
|
||||
use Flarum\Core\Post;
|
||||
use Flarum\Core\Discussion;
|
||||
use Flarum\Event\PostWasPosted;
|
||||
use Flarum\Event\PostWasDeleted;
|
||||
use Flarum\Event\PostWasHidden;
|
||||
use Flarum\Event\PostWasRestored;
|
||||
use Flarum\Event\DiscussionWasStarted;
|
||||
use Flarum\Event\DiscussionWasDeleted;
|
||||
use Illuminate\Contracts\Events\Dispatcher;
|
||||
|
||||
class UserMetadataUpdater
|
||||
@@ -44,7 +44,7 @@ class UserMetadataUpdater
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PostWasDeleted $event
|
||||
* @param \Flarum\Event\PostWasDeleted $event
|
||||
*/
|
||||
public function whenPostWasDeleted(PostWasDeleted $event)
|
||||
{
|
||||
@@ -60,7 +60,7 @@ class UserMetadataUpdater
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Flarum\Events\PostWasRestored $event
|
||||
* @param \Flarum\Event\PostWasRestored $event
|
||||
*/
|
||||
public function whenPostWasRestored(PostWasRestored $event)
|
||||
{
|
||||
@@ -76,7 +76,7 @@ class UserMetadataUpdater
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Flarum\Events\DiscussionWasDeleted $event
|
||||
* @param \Flarum\Event\DiscussionWasDeleted $event
|
||||
*/
|
||||
public function whenDiscussionWasDeleted(DiscussionWasDeleted $event)
|
||||
{
|
@@ -1,142 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* (c) Toby Zerner <toby.zerner@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core;
|
||||
|
||||
use Flarum\Events\ModelDates;
|
||||
use Flarum\Events\ModelRelationship;
|
||||
use Illuminate\Database\Eloquent\Model as Eloquent;
|
||||
use Illuminate\Database\Eloquent\Relations\Relation;
|
||||
use LogicException;
|
||||
|
||||
/**
|
||||
* Base model class, building on Eloquent.
|
||||
*
|
||||
* Adds the ability for custom relations to be added to a model during runtime.
|
||||
* These relations behave in the same way that you would expect; they can be
|
||||
* queried, eager loaded, and accessed as an attribute.
|
||||
*
|
||||
* Also has a scope method `whereVisibleTo` that scopes a query to only include
|
||||
* records that the user has permission to see.
|
||||
*/
|
||||
abstract class Model extends Eloquent
|
||||
{
|
||||
/**
|
||||
* Indicates if the model should be timestamped. Turn off by default.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
public $timestamps = false;
|
||||
|
||||
/**
|
||||
* An array of callbacks to be run once after the model is saved.
|
||||
*
|
||||
* @var callable[]
|
||||
*/
|
||||
public $afterSaveCallbacks = [];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function boot()
|
||||
{
|
||||
parent::boot();
|
||||
|
||||
static::saved(function (Model $model) {
|
||||
foreach ($model->afterSaveCallbacks as $callback) {
|
||||
$callback($model);
|
||||
}
|
||||
|
||||
$model->afterSaveCallbacks = [];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the attributes that should be converted to dates.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getDates()
|
||||
{
|
||||
static $dates = [];
|
||||
|
||||
$class = get_class($this);
|
||||
|
||||
if (! isset($dates[$class])) {
|
||||
event(new ModelDates($this, $this->dates));
|
||||
|
||||
$dates[$class] = $this->dates;
|
||||
}
|
||||
|
||||
return $dates[$class];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an attribute from the model. If nothing is found, attempt to load
|
||||
* a custom relation method with this key.
|
||||
*
|
||||
* @param string $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function getAttribute($key)
|
||||
{
|
||||
if (! is_null($value = parent::getAttribute($key))) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
// If a custom relation with this key has been set up, then we will load
|
||||
// and return results from the query and hydrate the relationship's
|
||||
// value on the "relationships" array.
|
||||
if (! $this->relationLoaded($key) && ($relation = $this->getCustomRelation($key))) {
|
||||
if (! $relation instanceof Relation) {
|
||||
throw new LogicException('Relationship method must return an object of type '
|
||||
. 'Illuminate\Database\Eloquent\Relations\Relation');
|
||||
}
|
||||
|
||||
return $this->relations[$key] = $relation->getResults();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a custom relation object.
|
||||
*
|
||||
* @param string $name
|
||||
* @return mixed
|
||||
*/
|
||||
protected function getCustomRelation($name)
|
||||
{
|
||||
return static::$dispatcher->until(
|
||||
new ModelRelationship($this, $name)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a callback to be run once after the model is saved.
|
||||
*
|
||||
* @param callable $callback
|
||||
* @return void
|
||||
*/
|
||||
public function afterSave($callback)
|
||||
{
|
||||
$this->afterSaveCallbacks[] = $callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function __call($method, $arguments)
|
||||
{
|
||||
if ($relation = $this->getCustomRelation($method)) {
|
||||
return $relation;
|
||||
}
|
||||
|
||||
return parent::__call($method, $arguments);
|
||||
}
|
||||
}
|
@@ -8,9 +8,9 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Notifications;
|
||||
namespace Flarum\Core;
|
||||
|
||||
use Flarum\Core\Model;
|
||||
use Flarum\Database\AbstractModel;
|
||||
|
||||
/**
|
||||
* Models a notification record in the database.
|
||||
@@ -26,9 +26,20 @@ use Flarum\Core\Model;
|
||||
* someone renamed a user's discussion. Its subject is a discussion, of which
|
||||
* the ID is stored in the `subject_id` column.
|
||||
*
|
||||
* @todo document database columns with @property
|
||||
* @property int $id
|
||||
* @property int $user_id
|
||||
* @property int|null $sender_id
|
||||
* @property string $type
|
||||
* @property int|null $subject_id
|
||||
* @property mixed|null $data
|
||||
* @property \Carbon\Carbon $time
|
||||
* @property bool $is_read
|
||||
* @property bool $is_deleted
|
||||
* @property \Flarum\Core\User|null $user
|
||||
* @property \Flarum\Core\User|null $sender
|
||||
* @property \Flarum\Database\AbstractModel|null $subject
|
||||
*/
|
||||
class Notification extends Model
|
||||
class Notification extends AbstractModel
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
@@ -44,7 +55,7 @@ class Notification extends Model
|
||||
* A map of notification types and the model classes to use for their
|
||||
* subjects. For example, the 'discussionRenamed' notification type, which
|
||||
* represents that a user's discussion was renamed, has the subject model
|
||||
* class 'Flarum\Core\Discussions\Discussion'.
|
||||
* class 'Flarum\Core\Discussion'.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
@@ -101,7 +112,7 @@ class Notification extends Model
|
||||
*/
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo('Flarum\Core\Users\User', 'user_id');
|
||||
return $this->belongsTo('Flarum\Core\User', 'user_id');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -111,7 +122,7 @@ class Notification extends Model
|
||||
*/
|
||||
public function sender()
|
||||
{
|
||||
return $this->belongsTo('Flarum\Core\Users\User', 'sender_id');
|
||||
return $this->belongsTo('Flarum\Core\User', 'sender_id');
|
||||
}
|
||||
|
||||
/**
|
@@ -8,26 +8,26 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Notifications;
|
||||
namespace Flarum\Core\Notification;
|
||||
|
||||
/**
|
||||
* A notification Blueprint, when instantiated, represents a notification about
|
||||
* A notification BlueprintInterface, when instantiated, represents a notification about
|
||||
* something. The blueprint is used by the NotificationSyncer to commit the
|
||||
* notification to the database.
|
||||
*/
|
||||
interface Blueprint
|
||||
interface BlueprintInterface
|
||||
{
|
||||
/**
|
||||
* Get the user that sent the notification.
|
||||
*
|
||||
* @return \Flarum\Core\Users\User|null
|
||||
* @return \Flarum\Core\User|null
|
||||
*/
|
||||
public function getSender();
|
||||
|
||||
/**
|
||||
* Get the model that is the subject of this activity.
|
||||
*
|
||||
* @return \Flarum\Core\Model|null
|
||||
* @return \Flarum\Database\AbstractModel|null
|
||||
*/
|
||||
public function getSubject();
|
||||
|
@@ -8,11 +8,11 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Notifications;
|
||||
namespace Flarum\Core\Notification;
|
||||
|
||||
use Flarum\Core\Posts\DiscussionRenamedPost;
|
||||
use Flarum\Core\Post\DiscussionRenamedPost;
|
||||
|
||||
class DiscussionRenamedBlueprint implements Blueprint
|
||||
class DiscussionRenamedBlueprint implements BlueprintInterface
|
||||
{
|
||||
/**
|
||||
* @var DiscussionRenamedPost
|
||||
@@ -64,6 +64,6 @@ class DiscussionRenamedBlueprint implements Blueprint
|
||||
*/
|
||||
public static function getSubjectModel()
|
||||
{
|
||||
return 'Flarum\Core\Discussions\Discussion';
|
||||
return 'Flarum\Core\Discussion';
|
||||
}
|
||||
}
|
@@ -8,9 +8,9 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Notifications;
|
||||
namespace Flarum\Core\Notification;
|
||||
|
||||
interface MailableBlueprint
|
||||
interface MailableInterface
|
||||
{
|
||||
/**
|
||||
* Get the name of the view to construct a notification email with.
|
@@ -8,9 +8,9 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Notifications;
|
||||
namespace Flarum\Core\Notification;
|
||||
|
||||
use Flarum\Core\Users\User;
|
||||
use Flarum\Core\User;
|
||||
use Illuminate\Contracts\Mail\Mailer;
|
||||
use Illuminate\Mail\Message;
|
||||
|
||||
@@ -30,10 +30,10 @@ class NotificationMailer
|
||||
}
|
||||
|
||||
/**
|
||||
* @param MailableBlueprint $blueprint
|
||||
* @param MailableInterface $blueprint
|
||||
* @param User $user
|
||||
*/
|
||||
public function send(MailableBlueprint $blueprint, User $user)
|
||||
public function send(MailableInterface $blueprint, User $user)
|
||||
{
|
||||
$this->mailer->send(
|
||||
$blueprint->getEmailView(),
|
@@ -8,42 +8,37 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Notifications;
|
||||
namespace Flarum\Core\Notification;
|
||||
|
||||
use Flarum\Core\Users\User;
|
||||
use Flarum\Events\RegisterNotificationTypes;
|
||||
use Flarum\Support\ServiceProvider;
|
||||
use Flarum\Core\Notification;
|
||||
use Flarum\Core\User;
|
||||
use Flarum\Event\ConfigureNotificationTypes;
|
||||
use Flarum\Foundation\AbstractServiceProvider;
|
||||
use Flarum\Extend;
|
||||
use ReflectionClass;
|
||||
|
||||
class NotificationsServiceProvider extends ServiceProvider
|
||||
class NotificationServiceProvider extends AbstractServiceProvider
|
||||
{
|
||||
/**
|
||||
* Bootstrap the application events.
|
||||
*
|
||||
* @return void
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
$events = $this->app->make('events');
|
||||
|
||||
$events->subscribe('Flarum\Core\Notifications\Listeners\DiscussionRenamedNotifier');
|
||||
|
||||
$this->registerNotificationTypes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register notification types.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function registerNotificationTypes()
|
||||
{
|
||||
$blueprints = [
|
||||
'Flarum\Core\Notifications\DiscussionRenamedBlueprint' => ['alert']
|
||||
'Flarum\Core\Notification\DiscussionRenamedBlueprint' => ['alert']
|
||||
];
|
||||
|
||||
event(new RegisterNotificationTypes($blueprints));
|
||||
$this->app->make('events')->fire(
|
||||
new ConfigureNotificationTypes($blueprints)
|
||||
);
|
||||
|
||||
foreach ($blueprints as $blueprint => $enabled) {
|
||||
Notification::setSubjectModel(
|
||||
@@ -57,7 +52,7 @@ class NotificationsServiceProvider extends ServiceProvider
|
||||
in_array('alert', $enabled)
|
||||
);
|
||||
|
||||
if ((new ReflectionClass($blueprint))->implementsInterface('Flarum\Core\Notifications\MailableBlueprint')) {
|
||||
if ((new ReflectionClass($blueprint))->implementsInterface('Flarum\Core\Notification\MailableInterface')) {
|
||||
User::addPreference(
|
||||
User::getNotificationPreferenceKey($type, 'email'),
|
||||
'boolval',
|
||||
@@ -66,13 +61,4 @@ class NotificationsServiceProvider extends ServiceProvider
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the service provider.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
}
|
||||
}
|
@@ -8,10 +8,12 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Notifications;
|
||||
namespace Flarum\Core\Notification;
|
||||
|
||||
use Flarum\Events\NotificationWillBeSent;
|
||||
use Flarum\Core\Users\User;
|
||||
use Flarum\Core\Notification;
|
||||
use Flarum\Core\Repository\NotificationRepository;
|
||||
use Flarum\Event\NotificationWillBeSent;
|
||||
use Flarum\Core\User;
|
||||
use Carbon\Carbon;
|
||||
|
||||
/**
|
||||
@@ -63,11 +65,11 @@ class NotificationSyncer
|
||||
* visible to anyone else. If it is being made visible for the first time,
|
||||
* attempt to send the user an email.
|
||||
*
|
||||
* @param Blueprint $blueprint
|
||||
* @param BlueprintInterface $blueprint
|
||||
* @param User[] $users
|
||||
* @return void
|
||||
*/
|
||||
public function sync(Blueprint $blueprint, array $users)
|
||||
public function sync(BlueprintInterface $blueprint, array $users)
|
||||
{
|
||||
$attributes = $this->getAttributes($blueprint);
|
||||
|
||||
@@ -118,10 +120,10 @@ class NotificationSyncer
|
||||
/**
|
||||
* Delete a notification for all users.
|
||||
*
|
||||
* @param Blueprint $blueprint
|
||||
* @param BlueprintInterface $blueprint
|
||||
* @return void
|
||||
*/
|
||||
public function delete(Blueprint $blueprint)
|
||||
public function delete(BlueprintInterface $blueprint)
|
||||
{
|
||||
Notification::where($this->getAttributes($blueprint))->update(['is_deleted' => true]);
|
||||
}
|
||||
@@ -129,10 +131,10 @@ class NotificationSyncer
|
||||
/**
|
||||
* Restore a notification for all users.
|
||||
*
|
||||
* @param Blueprint $blueprint
|
||||
* @param BlueprintInterface $blueprint
|
||||
* @return void
|
||||
*/
|
||||
public function restore(Blueprint $blueprint)
|
||||
public function restore(BlueprintInterface $blueprint)
|
||||
{
|
||||
Notification::where($this->getAttributes($blueprint))->update(['is_deleted' => false]);
|
||||
}
|
||||
@@ -158,10 +160,10 @@ class NotificationSyncer
|
||||
* Create a notification record and send an email (depending on user
|
||||
* preference) from a blueprint to a list of recipients.
|
||||
*
|
||||
* @param Blueprint $blueprint
|
||||
* @param BlueprintInterface $blueprint
|
||||
* @param User[] $recipients
|
||||
*/
|
||||
protected function sendNotifications(Blueprint $blueprint, array $recipients)
|
||||
protected function sendNotifications(BlueprintInterface $blueprint, array $recipients)
|
||||
{
|
||||
$now = Carbon::now('utc')->toDateTimeString();
|
||||
|
||||
@@ -178,7 +180,7 @@ class NotificationSyncer
|
||||
}, $recipients)
|
||||
);
|
||||
|
||||
if ($blueprint instanceof MailableBlueprint) {
|
||||
if ($blueprint instanceof MailableInterface) {
|
||||
$this->mailNotifications($blueprint, $recipients);
|
||||
}
|
||||
}
|
||||
@@ -186,10 +188,10 @@ class NotificationSyncer
|
||||
/**
|
||||
* Mail a notification to a list of users.
|
||||
*
|
||||
* @param MailableBlueprint $blueprint
|
||||
* @param MailableInterface $blueprint
|
||||
* @param User[] $recipients
|
||||
*/
|
||||
protected function mailNotifications(MailableBlueprint $blueprint, array $recipients)
|
||||
protected function mailNotifications(MailableInterface $blueprint, array $recipients)
|
||||
{
|
||||
foreach ($recipients as $user) {
|
||||
if ($user->shouldEmail($blueprint::getType())) {
|
||||
@@ -213,10 +215,10 @@ class NotificationSyncer
|
||||
* Construct an array of attributes to be stored in a notification record in
|
||||
* the database, given a notification blueprint.
|
||||
*
|
||||
* @param Blueprint $blueprint
|
||||
* @param BlueprintInterface $blueprint
|
||||
* @return array
|
||||
*/
|
||||
protected function getAttributes(Blueprint $blueprint)
|
||||
protected function getAttributes(BlueprintInterface $blueprint)
|
||||
{
|
||||
return [
|
||||
'type' => $blueprint::getType(),
|
@@ -8,14 +8,14 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Users;
|
||||
namespace Flarum\Core;
|
||||
|
||||
use Flarum\Core\Model;
|
||||
use Flarum\Database\AbstractModel;
|
||||
|
||||
/**
|
||||
* @todo document database columns with @property
|
||||
*/
|
||||
class PasswordToken extends Model
|
||||
class PasswordToken extends AbstractModel
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
@@ -58,6 +58,6 @@ class PasswordToken extends Model
|
||||
*/
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo('Flarum\Core\Users\User');
|
||||
return $this->belongsTo('Flarum\Core\User');
|
||||
}
|
||||
}
|
@@ -8,15 +8,15 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Groups;
|
||||
namespace Flarum\Core;
|
||||
|
||||
use Flarum\Core\Model;
|
||||
use Flarum\Database\AbstractModel;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
/**
|
||||
* @todo document database columns with @property
|
||||
*/
|
||||
class Permission extends Model
|
||||
class Permission extends AbstractModel
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
@@ -30,7 +30,7 @@ class Permission extends Model
|
||||
*/
|
||||
public function group()
|
||||
{
|
||||
return $this->belongsTo('Flarum\Core\Groups\Group', 'group_id');
|
||||
return $this->belongsTo('Flarum\Core\Group', 'group_id');
|
||||
}
|
||||
|
||||
/**
|
@@ -8,50 +8,46 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Posts;
|
||||
namespace Flarum\Core;
|
||||
|
||||
use DomainException;
|
||||
use Flarum\Events\PostWasDeleted;
|
||||
use Flarum\Core\Model;
|
||||
use Flarum\Core\Users\User;
|
||||
use Flarum\Core\Post\RegisteredTypesScope;
|
||||
use Flarum\Event\PostWasDeleted;
|
||||
use Flarum\Database\AbstractModel;
|
||||
use Flarum\Core\User;
|
||||
use Flarum\Core\Support\Locked;
|
||||
use Flarum\Core\Support\VisibleScope;
|
||||
use Flarum\Core\Support\EventGenerator;
|
||||
use Flarum\Core\Support\ValidatesBeforeSave;
|
||||
use Flarum\Core\Support\ScopeVisibilityTrait;
|
||||
use Flarum\Core\Support\EventGeneratorTrait;
|
||||
use Flarum\Core\Support\ValidateBeforeSaveTrait;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
/**
|
||||
* @todo document database columns with @property
|
||||
* @property int $id
|
||||
* @property int $discussion_id
|
||||
* @property int $number
|
||||
* @property \Carbon\Carbon $time
|
||||
* @property int|null $user_id
|
||||
* @property string|null $type
|
||||
* @property string|null $content
|
||||
* @property \Carbon\Carbon|null $edit_time
|
||||
* @property int|null $edit_user_id
|
||||
* @property \Carbon\Carbon|null $hide_time
|
||||
* @property int|null $hide_user_id
|
||||
* @property \Flarum\Core\Discussion|null $discussion
|
||||
* @property User|null $user
|
||||
* @property User|null $editUser
|
||||
* @property User|null $hideUser
|
||||
*/
|
||||
class Post extends Model
|
||||
class Post extends AbstractModel
|
||||
{
|
||||
use EventGenerator;
|
||||
use Locked;
|
||||
use VisibleScope;
|
||||
use ValidatesBeforeSave;
|
||||
use EventGeneratorTrait;
|
||||
use ScopeVisibilityTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $table = 'posts';
|
||||
|
||||
/**
|
||||
* The validation rules for this model.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $rules = [
|
||||
'discussion_id' => 'required|integer',
|
||||
'time' => 'required|date',
|
||||
'content' => 'required|max:65535',
|
||||
'number' => 'integer',
|
||||
'user_id' => 'integer',
|
||||
'edit_time' => 'date',
|
||||
'edit_user_id' => 'integer',
|
||||
'hide_time' => 'date',
|
||||
'hide_user_id' => 'integer',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@@ -133,7 +129,7 @@ class Post extends Model
|
||||
*/
|
||||
public function discussion()
|
||||
{
|
||||
return $this->belongsTo('Flarum\Core\Discussions\Discussion', 'discussion_id');
|
||||
return $this->belongsTo('Flarum\Core\Discussion', 'discussion_id');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -143,7 +139,7 @@ class Post extends Model
|
||||
*/
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo('Flarum\Core\Users\User', 'user_id');
|
||||
return $this->belongsTo('Flarum\Core\User', 'user_id');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -153,7 +149,7 @@ class Post extends Model
|
||||
*/
|
||||
public function editUser()
|
||||
{
|
||||
return $this->belongsTo('Flarum\Core\Users\User', 'edit_user_id');
|
||||
return $this->belongsTo('Flarum\Core\User', 'edit_user_id');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -163,7 +159,7 @@ class Post extends Model
|
||||
*/
|
||||
public function hideUser()
|
||||
{
|
||||
return $this->belongsTo('Flarum\Core\Users\User', 'hide_user_id');
|
||||
return $this->belongsTo('Flarum\Core\User', 'hide_user_id');
|
||||
}
|
||||
|
||||
/**
|
@@ -8,9 +8,11 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Posts;
|
||||
namespace Flarum\Core\Post;
|
||||
|
||||
abstract class EventPost extends Post
|
||||
use Flarum\Core\Post;
|
||||
|
||||
abstract class AbstractEventPost extends Post
|
||||
{
|
||||
/**
|
||||
* Unserialize the content attribute from the database's JSON value.
|
@@ -8,18 +8,22 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Posts;
|
||||
namespace Flarum\Core\Post;
|
||||
|
||||
use DomainException;
|
||||
use Flarum\Core\Formatter\Formatter;
|
||||
use Flarum\Events\PostWasPosted;
|
||||
use Flarum\Events\PostWasRevised;
|
||||
use Flarum\Events\PostWasHidden;
|
||||
use Flarum\Events\PostWasRestored;
|
||||
use Flarum\Core\Users\User;
|
||||
use Flarum\Core\Post;
|
||||
use Flarum\Formatter\Formatter;
|
||||
use Flarum\Event\PostWasPosted;
|
||||
use Flarum\Event\PostWasRevised;
|
||||
use Flarum\Event\PostWasHidden;
|
||||
use Flarum\Event\PostWasRestored;
|
||||
use Flarum\Core\User;
|
||||
|
||||
/**
|
||||
* A standard comment in a discussion.
|
||||
*
|
||||
* @property string $parsed_content
|
||||
* @property string $content_html
|
||||
*/
|
||||
class CommentPost extends Post
|
||||
{
|
||||
@@ -31,7 +35,7 @@ class CommentPost extends Post
|
||||
/**
|
||||
* The text formatter instance.
|
||||
*
|
||||
* @var Formatter
|
||||
* @var \Flarum\Formatter\Formatter
|
||||
*/
|
||||
protected static $formatter;
|
||||
|
||||
@@ -161,7 +165,7 @@ class CommentPost extends Post
|
||||
/**
|
||||
* Get the text formatter instance.
|
||||
*
|
||||
* @return Formatter
|
||||
* @return \Flarum\Formatter\Formatter
|
||||
*/
|
||||
public static function getFormatter()
|
||||
{
|
||||
@@ -171,7 +175,7 @@ class CommentPost extends Post
|
||||
/**
|
||||
* Set the text formatter instance.
|
||||
*
|
||||
* @param Formatter $formatter
|
||||
* @param \Flarum\Formatter\Formatter $formatter
|
||||
*/
|
||||
public static function setFormatter(Formatter $formatter)
|
||||
{
|
@@ -8,7 +8,9 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Posts;
|
||||
namespace Flarum\Core\Post;
|
||||
|
||||
use Flarum\Core\Post;
|
||||
|
||||
/**
|
||||
* A post which indicates that a discussion's title was changed.
|
||||
@@ -16,7 +18,7 @@ namespace Flarum\Core\Posts;
|
||||
* The content is stored as a sequential array containing the old title and the
|
||||
* new title.
|
||||
*/
|
||||
class DiscussionRenamedPost extends EventPost implements MergeablePost
|
||||
class DiscussionRenamedPost extends AbstractEventPost implements MergeableInterface
|
||||
{
|
||||
/**
|
||||
* @inheritdoc
|
@@ -8,7 +8,9 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Posts;
|
||||
namespace Flarum\Core\Post;
|
||||
|
||||
use Flarum\Core\Post;
|
||||
|
||||
/**
|
||||
* A post that has the ability to be merged into an adjacent post.
|
||||
@@ -17,7 +19,7 @@ namespace Flarum\Core\Posts;
|
||||
* if a "discussion renamed" post is posted immediately after another
|
||||
* "discussion renamed" post, then the new one will be merged into the old one.
|
||||
*/
|
||||
interface MergeablePost
|
||||
interface MergeableInterface
|
||||
{
|
||||
/**
|
||||
* Save the model, given that it is going to appear immediately after the
|
@@ -8,7 +8,7 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Posts;
|
||||
namespace Flarum\Core\Post;
|
||||
|
||||
use Illuminate\Database\Eloquent\ScopeInterface;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
@@ -1,54 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* (c) Toby Zerner <toby.zerner@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Posts\Commands;
|
||||
|
||||
use Flarum\Core\Posts\PostRepository;
|
||||
use Flarum\Events\PostWillBeDeleted;
|
||||
use Flarum\Core\Support\DispatchesEvents;
|
||||
|
||||
class DeletePostHandler
|
||||
{
|
||||
use DispatchesEvents;
|
||||
|
||||
/**
|
||||
* @var PostRepository
|
||||
*/
|
||||
protected $posts;
|
||||
|
||||
/**
|
||||
* @param PostRepository $posts
|
||||
*/
|
||||
public function __construct(PostRepository $posts)
|
||||
{
|
||||
$this->posts = $posts;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DeletePost $command
|
||||
* @return \Flarum\Core\Posts\Post
|
||||
*/
|
||||
public function handle(DeletePost $command)
|
||||
{
|
||||
$actor = $command->actor;
|
||||
|
||||
$post = $this->posts->findOrFail($command->postId, $actor);
|
||||
|
||||
$post->assertCan($actor, 'delete');
|
||||
|
||||
event(new PostWillBeDeleted($post, $actor, $command->data));
|
||||
|
||||
$post->delete();
|
||||
|
||||
$this->dispatchEventsFor($post);
|
||||
|
||||
return $post;
|
||||
}
|
||||
}
|
@@ -1,118 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* (c) Toby Zerner <toby.zerner@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Posts;
|
||||
|
||||
use Flarum\Core\Discussions\Discussion;
|
||||
use Flarum\Core\Users\User;
|
||||
use Flarum\Events\ModelAllow;
|
||||
use Flarum\Events\RegisterPostTypes;
|
||||
use Flarum\Events\ScopePostVisibility;
|
||||
use Flarum\Support\ServiceProvider;
|
||||
use Flarum\Extend;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class PostsServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Bootstrap the application events.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
Post::setValidator($this->app->make('validator'));
|
||||
|
||||
CommentPost::setFormatter($this->app->make('flarum.formatter'));
|
||||
|
||||
$this->registerPostTypes();
|
||||
|
||||
$events = $this->app->make('events');
|
||||
$settings = $this->app->make('Flarum\Core\Settings\SettingsRepository');
|
||||
|
||||
$events->listen(ModelAllow::class, function (ModelAllow $event) use ($settings) {
|
||||
if ($event->model instanceof Post) {
|
||||
$post = $event->model;
|
||||
$action = $event->action;
|
||||
$actor = $event->actor;
|
||||
|
||||
if ($action === 'view' &&
|
||||
(! $post->hide_time || $post->user_id == $actor->id || $post->can($actor, 'edit'))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// A post is allowed to be edited if the user has permission to moderate
|
||||
// the discussion which it's in, or if they are the author and the post
|
||||
// hasn't been deleted by someone else.
|
||||
if ($action === 'edit') {
|
||||
if ($post->discussion->can($actor, 'editPosts')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($post->user_id == $actor->id && (! $post->hide_time || $post->hide_user_id == $actor->id)) {
|
||||
$allowEditing = $settings->get('allow_post_editing');
|
||||
|
||||
if ($allowEditing === '-1' ||
|
||||
($allowEditing === 'reply' && $event->model->number >= $event->model->discussion->last_post_number) ||
|
||||
($event->model->time->diffInMinutes(Carbon::now()) < $allowEditing)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($post->discussion->can($actor, $action.'Posts')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// When fetching a discussion's posts: if the user doesn't have permission
|
||||
// to moderate the discussion, then they can't see posts that have been
|
||||
// hidden by someone other than themself.
|
||||
$events->listen(ScopePostVisibility::class, function (ScopePostVisibility $event) {
|
||||
$user = $event->actor;
|
||||
|
||||
if (! $event->discussion->can($user, 'editPosts')) {
|
||||
$event->query->where(function ($query) use ($user) {
|
||||
$query->whereNull('hide_time')
|
||||
->orWhere('user_id', $user->id);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Register post types.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function registerPostTypes()
|
||||
{
|
||||
$models = [
|
||||
'Flarum\Core\Posts\CommentPost',
|
||||
'Flarum\Core\Posts\DiscussionRenamedPost'
|
||||
];
|
||||
|
||||
event(new RegisterPostTypes($models));
|
||||
|
||||
foreach ($models as $model) {
|
||||
Post::setModel($model::$type, $model);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the service provider.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
}
|
||||
}
|
@@ -8,10 +8,11 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Discussions;
|
||||
namespace Flarum\Core\Repository;
|
||||
|
||||
use Flarum\Core\Discussion;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Flarum\Core\Users\User;
|
||||
use Flarum\Core\User;
|
||||
use Illuminate\Database\Query\Expression;
|
||||
|
||||
class DiscussionRepository
|
||||
@@ -32,7 +33,7 @@ class DiscussionRepository
|
||||
*
|
||||
* @param integer $id
|
||||
* @param User $user
|
||||
* @return \Flarum\Core\Discussions\Discussion
|
||||
* @return \Flarum\Core\Discussion
|
||||
*/
|
||||
public function findOrFail($id, User $user = null)
|
||||
{
|
@@ -8,9 +8,10 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Groups;
|
||||
namespace Flarum\Core\Repository;
|
||||
|
||||
use Flarum\Core\Users\User;
|
||||
use Flarum\Core\Group;
|
||||
use Flarum\Core\User;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class GroupRepository
|
@@ -8,9 +8,10 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Notifications;
|
||||
namespace Flarum\Core\Repository;
|
||||
|
||||
use Flarum\Core\Users\User;
|
||||
use Flarum\Core\Notification;
|
||||
use Flarum\Core\User;
|
||||
|
||||
class NotificationRepository
|
||||
{
|
@@ -8,33 +8,13 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Posts;
|
||||
namespace Flarum\Core\Repository;
|
||||
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Flarum\Core\Post;
|
||||
use Flarum\Event\ScopePostVisibility;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use Flarum\Core\Users\User;
|
||||
use Flarum\Core\Discussions\Discussion;
|
||||
use Flarum\Core\Discussions\Search\Fulltext\Driver;
|
||||
|
||||
// TODO: In some cases, the use of a post repository incurs extra query expense,
|
||||
// because for every post retrieved we need to check if the discussion it's in
|
||||
// is visible. Especially when retrieving a discussion's posts, we can end up
|
||||
// with an inefficient chain of queries like this:
|
||||
// 1. Api\Discussions\ShowAction: get discussion (will exit if not visible)
|
||||
// 2. Discussion@postsVisibleTo: get discussion tags (for post visibility purposes)
|
||||
// 3. Discussion@postsVisibleTo: get post IDs
|
||||
// 4. EloquentPostRepository@getIndexForNumber: get discussion
|
||||
// 5. EloquentPostRepository@getIndexForNumber: get discussion tags (for post visibility purposes)
|
||||
// 6. EloquentPostRepository@getIndexForNumber: get post index for number
|
||||
// 7. EloquentPostRepository@findWhere: get post IDs for discussion to check for discussion visibility
|
||||
// 8. EloquentPostRepository@findWhere: get post IDs in visible discussions
|
||||
// 9. EloquentPostRepository@findWhere: get posts
|
||||
// 10. EloquentPostRepository@findWhere: eager load discussion onto posts
|
||||
// 11. EloquentPostRepository@findWhere: get discussion tags to filter visible posts
|
||||
// 12. Api\Discussions\ShowAction: eager load users
|
||||
// 13. Api\Discussions\ShowAction: eager load groups
|
||||
// 14. Api\Discussions\ShowAction: eager load mentions
|
||||
// 14. Serializers\DiscussionSerializer: load discussion-user state
|
||||
use Flarum\Core\User;
|
||||
use Flarum\Core\Discussion;
|
||||
|
||||
class PostRepository
|
||||
{
|
||||
@@ -43,8 +23,8 @@ class PostRepository
|
||||
* user, or throw an exception.
|
||||
*
|
||||
* @param integer $id
|
||||
* @param \Flarum\Core\Users\User $actor
|
||||
* @return \Flarum\Core\Posts\Post
|
||||
* @param \Flarum\Core\User $actor
|
||||
* @return \Flarum\Core\Post
|
||||
*
|
||||
* @throws \Illuminate\Database\Eloquent\ModelNotFoundException
|
||||
*/
|
||||
@@ -64,13 +44,13 @@ class PostRepository
|
||||
* are visible to a certain user, and/or using other criteria.
|
||||
*
|
||||
* @param array $where
|
||||
* @param \Flarum\Core\Users\User|null $actor
|
||||
* @param \Flarum\Core\User|null $actor
|
||||
* @param array $sort
|
||||
* @param integer $count
|
||||
* @param integer $start
|
||||
* @return \Illuminate\Database\Eloquent\Collection
|
||||
*/
|
||||
public function findWhere($where = [], User $actor = null, $sort = [], $count = null, $start = 0)
|
||||
public function findWhere(array $where = [], User $actor = null, $sort = [], $count = null, $start = 0)
|
||||
{
|
||||
$query = Post::where($where)
|
||||
->skip($start)
|
||||
@@ -90,14 +70,24 @@ class PostRepository
|
||||
* certain user.
|
||||
*
|
||||
* @param array $ids
|
||||
* @param \Flarum\Core\Users\User|null $actor
|
||||
* @param \Flarum\Core\User|null $actor
|
||||
* @return \Illuminate\Database\Eloquent\Collection
|
||||
*/
|
||||
public function findByIds(array $ids, User $actor = null)
|
||||
{
|
||||
$visibleIds = $this->filterDiscussionVisibleTo($ids, $actor);
|
||||
$discussions = $this->getDiscussionsForPosts($ids, $actor);
|
||||
|
||||
$posts = Post::with('discussion')->whereIn('id', $visibleIds)->get();
|
||||
$posts = Post::whereIn('id', $ids)
|
||||
->where(function ($query) use ($discussions, $actor) {
|
||||
foreach ($discussions as $discussion) {
|
||||
$query->orWhere(function ($query) use ($discussion, $actor) {
|
||||
$query->where('discussion_id', $discussion->id);
|
||||
|
||||
event(new ScopePostVisibility($discussion, $query, $actor));
|
||||
});
|
||||
}
|
||||
})
|
||||
->get();
|
||||
|
||||
$posts = $posts->sort(function ($a, $b) use ($ids) {
|
||||
$aPos = array_search($a->id, $ids);
|
||||
@@ -110,7 +100,7 @@ class PostRepository
|
||||
return $aPos < $bPos ? -1 : 1;
|
||||
});
|
||||
|
||||
return $this->filterVisibleTo($posts, $actor);
|
||||
return $posts;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -120,7 +110,7 @@ class PostRepository
|
||||
*
|
||||
* @param integer $discussionId
|
||||
* @param integer $number
|
||||
* @param \Flarum\Core\Users\User|null $actor
|
||||
* @param \Flarum\Core\User|null $actor
|
||||
* @return integer
|
||||
*/
|
||||
public function getIndexForNumber($discussionId, $number, User $actor = null)
|
||||
@@ -142,29 +132,12 @@ class PostRepository
|
||||
return $query->count();
|
||||
}
|
||||
|
||||
protected function filterDiscussionVisibleTo($ids, User $actor)
|
||||
protected function getDiscussionsForPosts($postIds, User $actor)
|
||||
{
|
||||
// For each post ID, we need to make sure that the discussion it's in
|
||||
// is visible to the user.
|
||||
if ($actor) {
|
||||
$ids = Discussion::join('posts', 'discussions.id', '=', 'posts.discussion_id')
|
||||
->whereIn('posts.id', $ids)
|
||||
->whereVisibleTo($actor)
|
||||
->get(['posts.id'])
|
||||
->lists('id');
|
||||
}
|
||||
|
||||
return $ids;
|
||||
}
|
||||
|
||||
protected function filterVisibleTo($posts, User $actor)
|
||||
{
|
||||
if ($actor) {
|
||||
$posts = $posts->filter(function ($post) use ($actor) {
|
||||
return $post->can($actor, 'view');
|
||||
});
|
||||
}
|
||||
|
||||
return $posts;
|
||||
return Discussion::whereIn('id', function ($query) use ($postIds) {
|
||||
$query->select('discussion_id')->from('posts')->whereIn('id', $postIds);
|
||||
})
|
||||
->whereVisibleTo($actor)
|
||||
->get();
|
||||
}
|
||||
}
|
@@ -8,8 +8,9 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Users;
|
||||
namespace Flarum\Core\Repository;
|
||||
|
||||
use Flarum\Core\User;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class UserRepository
|
@@ -10,7 +10,7 @@
|
||||
|
||||
namespace Flarum\Core\Search;
|
||||
|
||||
abstract class RegexGambit implements Gambit
|
||||
abstract class AbstractRegexGambit implements GambitInterface
|
||||
{
|
||||
/**
|
||||
* The regex pattern to match the bit against.
|
||||
@@ -22,7 +22,7 @@ abstract class RegexGambit implements Gambit
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function apply(Search $search, $bit)
|
||||
public function apply(AbstractSearch $search, $bit)
|
||||
{
|
||||
if ($matches = $this->match($bit)) {
|
||||
list($negate) = array_splice($matches, 1, 1);
|
||||
@@ -49,11 +49,11 @@ abstract class RegexGambit implements Gambit
|
||||
/**
|
||||
* Apply conditions to the search, given that the gambit was matched.
|
||||
*
|
||||
* @param Search $search The search object.
|
||||
* @param AbstractSearch $search The search object.
|
||||
* @param array $matches An array of matches from the search bit.
|
||||
* @param bool $negate Whether or not the bit was negated, and thus whether
|
||||
* or not the conditions should be negated.
|
||||
* @return mixed
|
||||
*/
|
||||
abstract protected function conditions(Search $search, array $matches, $negate);
|
||||
abstract protected function conditions(AbstractSearch $search, array $matches, $negate);
|
||||
}
|
@@ -10,7 +10,7 @@
|
||||
|
||||
namespace Flarum\Core\Search;
|
||||
|
||||
use Flarum\Core\Users\User;
|
||||
use Flarum\Core\User;
|
||||
use Illuminate\Database\Query\Builder;
|
||||
|
||||
/**
|
||||
@@ -18,7 +18,7 @@ use Illuminate\Database\Query\Builder;
|
||||
* the search query, the user performing the search, the fallback sort order,
|
||||
* and a log of which gambits have been used.
|
||||
*/
|
||||
abstract class Search
|
||||
abstract class AbstractSearch
|
||||
{
|
||||
/**
|
||||
* @var Builder
|
||||
@@ -36,7 +36,7 @@ abstract class Search
|
||||
protected $defaultSort = [];
|
||||
|
||||
/**
|
||||
* @var Gambit[]
|
||||
* @var GambitInterface[]
|
||||
*/
|
||||
protected $activeGambits = [];
|
||||
|
||||
@@ -97,7 +97,7 @@ abstract class Search
|
||||
/**
|
||||
* Get a list of the gambits that are active in this search.
|
||||
*
|
||||
* @return Gambit[]
|
||||
* @return GambitInterface[]
|
||||
*/
|
||||
public function getActiveGambits()
|
||||
{
|
||||
@@ -107,10 +107,10 @@ abstract class Search
|
||||
/**
|
||||
* Add a gambit as being active in this search.
|
||||
*
|
||||
* @param Gambit $gambit
|
||||
* @param GambitInterface $gambit
|
||||
* @return void
|
||||
*/
|
||||
public function addActiveGambit(Gambit $gambit)
|
||||
public function addActiveGambit(GambitInterface $gambit)
|
||||
{
|
||||
$this->activeGambits[] = $gambit;
|
||||
}
|
@@ -10,15 +10,15 @@
|
||||
|
||||
namespace Flarum\Core\Search;
|
||||
|
||||
trait AppliesParametersToSearch
|
||||
trait ApplySearchParametersTrait
|
||||
{
|
||||
/**
|
||||
* Apply sort criteria to a discussion search.
|
||||
*
|
||||
* @param Search $search
|
||||
* @param AbstractSearch $search
|
||||
* @param array $sort
|
||||
*/
|
||||
protected function applySort(Search $search, array $sort = null)
|
||||
protected function applySort(AbstractSearch $search, array $sort = null)
|
||||
{
|
||||
$sort = $sort ?: $search->getDefaultSort();
|
||||
|
||||
@@ -34,10 +34,10 @@ trait AppliesParametersToSearch
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Search $search
|
||||
* @param AbstractSearch $search
|
||||
* @param int $offset
|
||||
*/
|
||||
protected function applyOffset(Search $search, $offset)
|
||||
protected function applyOffset(AbstractSearch $search, $offset)
|
||||
{
|
||||
if ($offset > 0) {
|
||||
$search->getQuery()->skip($offset);
|
||||
@@ -45,10 +45,10 @@ trait AppliesParametersToSearch
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Search $search
|
||||
* @param AbstractSearch $search
|
||||
* @param int|null $limit
|
||||
*/
|
||||
protected function applyLimit(Search $search, $limit)
|
||||
protected function applyLimit(AbstractSearch $search, $limit)
|
||||
{
|
||||
if ($limit > 0) {
|
||||
$search->getQuery()->take($limit);
|
@@ -8,16 +8,16 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Discussions\Search;
|
||||
namespace Flarum\Core\Search\Discussion;
|
||||
|
||||
use Flarum\Core\Search\Search;
|
||||
use Flarum\Core\Search\AbstractSearch;
|
||||
|
||||
/**
|
||||
* An object which represents the internal state of a search for discussions:
|
||||
* the search query, the user performing the search, the fallback sort order,
|
||||
* relevant post information, and a log of which gambits have been used.
|
||||
*/
|
||||
class DiscussionSearch extends Search
|
||||
class DiscussionSearch extends AbstractSearch
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
@@ -8,16 +8,15 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Discussions\Search;
|
||||
namespace Flarum\Core\Search\Discussion;
|
||||
|
||||
use Flarum\Core\Discussions\Discussion;
|
||||
use Flarum\Core\Search\AppliesParametersToSearch;
|
||||
use Flarum\Core\Discussion;
|
||||
use Flarum\Core\Search\ApplySearchParametersTrait;
|
||||
use Flarum\Core\Search\SearchCriteria;
|
||||
use Flarum\Core\Search\SearcherInterface;
|
||||
use Flarum\Core\Search\GambitManager;
|
||||
use Flarum\Core\Discussions\DiscussionRepository;
|
||||
use Flarum\Core\Posts\PostRepository;
|
||||
use Flarum\Events\DiscussionSearchWillBePerformed;
|
||||
use Flarum\Core\Repository\DiscussionRepository;
|
||||
use Flarum\Core\Repository\PostRepository;
|
||||
use Flarum\Event\DiscussionSearchWillBePerformed;
|
||||
use Flarum\Core\Search\SearchResults;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
|
||||
@@ -27,7 +26,7 @@ use Illuminate\Database\Eloquent\Collection;
|
||||
*/
|
||||
class DiscussionSearcher
|
||||
{
|
||||
use AppliesParametersToSearch;
|
||||
use ApplySearchParametersTrait;
|
||||
|
||||
/**
|
||||
* @var GambitManager
|
||||
@@ -82,6 +81,7 @@ class DiscussionSearcher
|
||||
$this->applyOffset($search, $offset);
|
||||
$this->applyLimit($search, $limit + 1);
|
||||
|
||||
// TODO: inject dispatcher
|
||||
event(new DiscussionSearchWillBePerformed($search, $criteria));
|
||||
|
||||
// Execute the search query and retrieve the results. We get one more
|
||||
@@ -89,7 +89,9 @@ class DiscussionSearcher
|
||||
// results. If there are, we will get rid of that extra result.
|
||||
$discussions = $query->get();
|
||||
|
||||
if ($areMoreResults = ($limit > 0 && $discussions->count() > $limit)) {
|
||||
$areMoreResults = $limit > 0 && $discussions->count() > $limit;
|
||||
|
||||
if ($areMoreResults) {
|
||||
$discussions->pop();
|
||||
}
|
||||
|
@@ -8,9 +8,9 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Discussions\Search\Fulltext;
|
||||
namespace Flarum\Core\Search\Discussion\Fulltext;
|
||||
|
||||
interface Driver
|
||||
interface DriverInterface
|
||||
{
|
||||
/**
|
||||
* Return an array of arrays of post IDs, grouped by discussion ID, which
|
@@ -8,11 +8,11 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Discussions\Search\Fulltext;
|
||||
namespace Flarum\Core\Search\Discussion\Fulltext;
|
||||
|
||||
use Flarum\Core\Posts\Post;
|
||||
use Flarum\Core\Post;
|
||||
|
||||
class MySqlFulltextDriver implements Driver
|
||||
class MySqlFulltextDriver implements DriverInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
@@ -8,15 +8,15 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Core\Discussions\Search\Gambits;
|
||||
namespace Flarum\Core\Search\Discussion\Gambit;
|
||||
|
||||
use Flarum\Core\Discussions\Search\DiscussionSearch;
|
||||
use Flarum\Core\Users\UserRepository;
|
||||
use Flarum\Core\Search\RegexGambit;
|
||||
use Flarum\Core\Search\Search;
|
||||
use Flarum\Core\Search\Discussion\DiscussionSearch;
|
||||
use Flarum\Core\Repository\UserRepository;
|
||||
use Flarum\Core\Search\AbstractRegexGambit;
|
||||
use Flarum\Core\Search\AbstractSearch;
|
||||
use LogicException;
|
||||
|
||||
class AuthorGambit extends RegexGambit
|
||||
class AuthorGambit extends AbstractRegexGambit
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
@@ -29,7 +29,7 @@ class AuthorGambit extends RegexGambit
|
||||
protected $users;
|
||||
|
||||
/**
|
||||
* @param UserRepository $users
|
||||
* @param \Flarum\Core\Repository\UserRepository $users
|
||||
*/
|
||||
public function __construct(UserRepository $users)
|
||||
{
|
||||
@@ -39,7 +39,7 @@ class AuthorGambit extends RegexGambit
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function conditions(Search $search, array $matches, $negate)
|
||||
protected function conditions(AbstractSearch $search, array $matches, $negate)
|
||||
{
|
||||
if (! $search instanceof DiscussionSearch) {
|
||||
throw new LogicException('This gambit can only be applied on a DiscussionSearch');
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user