1
0
mirror of https://github.com/flarum/core.git synced 2025-10-12 07:24:27 +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:
Toby Zerner
2015-10-08 14:28:02 +10:30
parent 8c7cdb184f
commit dd67291ce0
434 changed files with 8676 additions and 7997 deletions

View File

@@ -0,0 +1,29 @@
<?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;
class ConfirmEmail
{
/**
* The email confirmation token.
*
* @var string
*/
public $token;
/**
* @param string $token The email confirmation token.
*/
public function __construct($token)
{
$this->token = $token;
}
}

View File

@@ -0,0 +1,59 @@
<?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\EmailToken;
use Flarum\Core\Repository\UserRepository;
use Flarum\Core\Support\DispatchEventsTrait;
use Illuminate\Contracts\Events\Dispatcher;
class ConfirmEmailHandler
{
use DispatchEventsTrait;
/**
* @var UserRepository
*/
protected $users;
/**
* @param UserRepository $users
*/
public function __construct(Dispatcher $events, UserRepository $users)
{
$this->events = $events;
$this->users = $users;
}
/**
* @param ConfirmEmail $command
* @return \Flarum\Core\User
*/
public function handle(ConfirmEmail $command)
{
/** @var EmailToken $token */
$token = EmailToken::validOrFail($command->token);
$user = $token->user;
$user->changeEmail($token->email);
if (! $user->is_activated) {
$user->activate();
}
$user->save();
$this->dispatchEventsFor($user);
$token->delete();
return $user;
}
}

View File

@@ -0,0 +1,40 @@
<?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\User;
class CreateGroup
{
/**
* The user performing the action.
*
* @var User
*/
public $actor;
/**
* The attributes of the new group.
*
* @var array
*/
public $data;
/**
* @param User $actor The user performing the action.
* @param array $data The attributes of the new group.
*/
public function __construct(User $actor, array $data)
{
$this->actor = $actor;
$this->data = $data;
}
}

View 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\Group;
use Flarum\Event\GroupWillBeSaved;
use Flarum\Core\Support\DispatchEventsTrait;
use Illuminate\Contracts\Events\Dispatcher;
class CreateGroupHandler
{
use DispatchEventsTrait;
use AssertPermissionTrait;
/**
* @param Dispatcher $events
*/
public function __construct(Dispatcher $events)
{
$this->events = $events;
}
/**
* @param CreateGroup $command
* @return Group
* @throws PermissionDeniedException
*/
public function handle(CreateGroup $command)
{
$actor = $command->actor;
$data = $command->data;
$this->assertCan($actor, 'createGroup');
$group = Group::build(
array_get($data, 'attributes.nameSingular'),
array_get($data, 'attributes.namePlural'),
array_get($data, 'attributes.color'),
array_get($data, 'attributes.icon')
);
$this->events->fire(
new GroupWillBeSaved($group, $actor, $data)
);
$group->save();
$this->dispatchEventsFor($group, $actor);
return $group;
}
}

View File

@@ -0,0 +1,40 @@
<?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\User;
class DeleteAvatar
{
/**
* The ID of the user to delete the avatar of.
*
* @var int
*/
public $userId;
/**
* The user performing the action.
*
* @var User
*/
public $actor;
/**
* @param int $userId The ID of the user to delete the avatar of.
* @param User $actor The user performing the action.
*/
public function __construct($userId, User $actor)
{
$this->userId = $userId;
$this->actor = $actor;
}
}

View File

@@ -0,0 +1,80 @@
<?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\Event\AvatarWillBeDeleted;
use Flarum\Core\Repository\UserRepository;
use Flarum\Core\Support\DispatchEventsTrait;
use Illuminate\Contracts\Events\Dispatcher;
use League\Flysystem\FilesystemInterface;
class DeleteAvatarHandler
{
use DispatchEventsTrait;
use AssertPermissionTrait;
/**
* @var UserRepository
*/
protected $users;
/**
* @var FilesystemInterface
*/
protected $uploadDir;
/**
* @param Dispatcher $events
* @param UserRepository $users
* @param 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\User
* @throws PermissionDeniedException
*/
public function handle(DeleteAvatar $command)
{
$actor = $command->actor;
$user = $this->users->findOrFail($command->userId);
if ($actor->id !== $user->id) {
$this->assertCan($actor, 'edit', $user);
}
$avatarPath = $user->avatar_path;
$user->changeAvatarPath(null);
$this->events->fire(
new AvatarWillBeDeleted($user, $actor)
);
$user->save();
if ($this->uploadDir->has($avatarPath)) {
$this->uploadDir->delete($avatarPath);
}
$this->dispatchEventsFor($user, $actor);
return $user;
}
}

View File

@@ -0,0 +1,51 @@
<?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\User;
class DeleteDiscussion
{
/**
* The ID of the discussion to delete.
*
* @var int
*/
public $discussionId;
/**
* The user performing the action.
*
* @var User
*/
public $actor;
/**
* Any other user input associated with the action. This is unused by
* default, but may be used by extensions.
*
* @var array
*/
public $data;
/**
* @param int $discussionId The ID of the discussion to delete.
* @param User $actor The user performing the action.
* @param array $data Any other user input associated with the action. This
* is unused by default, but may be used by extensions.
*/
public function __construct($discussionId, User $actor, array $data = [])
{
$this->discussionId = $discussionId;
$this->actor = $actor;
$this->data = $data;
}
}

View 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;
}
}

View File

@@ -0,0 +1,52 @@
<?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\Group;
use Flarum\Core\User;
class DeleteGroup
{
/**
* The ID of the group to delete.
*
* @var int
*/
public $groupId;
/**
* The user performing the action.
*
* @var User
*/
public $actor;
/**
* Any other group input associated with the action. This is unused by
* default, but may be used by extensions.
*
* @var array
*/
public $data;
/**
* @param int $groupId The ID of the group to delete.
* @param User $actor The user performing the action.
* @param array $data Any other group input associated with the action. This
* is unused by default, but may be used by extensions.
*/
public function __construct($groupId, User $actor, array $data = [])
{
$this->groupId = $groupId;
$this->actor = $actor;
$this->data = $data;
}
}

View 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;
}
}

View File

@@ -0,0 +1,51 @@
<?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\User;
class DeletePost
{
/**
* The ID of the post to delete.
*
* @var int
*/
public $postId;
/**
* The user performing the action.
*
* @var User
*/
public $actor;
/**
* Any other user input associated with the action. This is unused by
* default, but may be used by extensions.
*
* @var array
*/
public $data;
/**
* @param int $postId The ID of the post to delete.
* @param User $actor The user performing the action.
* @param array $data Any other user input associated with the action. This
* is unused by default, but may be used by extensions.
*/
public function __construct($postId, User $actor, array $data = [])
{
$this->postId = $postId;
$this->actor = $actor;
$this->data = $data;
}
}

View 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;
}
}

View File

@@ -0,0 +1,51 @@
<?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\User;
class DeleteUser
{
/**
* The ID of the user to delete.
*
* @var int
*/
public $userId;
/**
* The user performing the action.
*
* @var User
*/
public $actor;
/**
* Any other user input associated with the action. This is unused by
* default, but may be used by extensions.
*
* @var array
*/
public $data;
/**
* @param int $userId The ID of the user to delete.
* @param User $actor The user performing the action.
* @param array $data Any other user input associated with the action. This
* is unused by default, but may be used by extensions.
*/
public function __construct($userId, User $actor, array $data = [])
{
$this->userId = $userId;
$this->actor = $actor;
$this->data = $data;
}
}

View 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;
}
}

View File

@@ -0,0 +1,49 @@
<?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\User;
class EditDiscussion
{
/**
* The ID of the discussion to edit.
*
* @var integer
*/
public $discussionId;
/**
* The user performing the action.
*
* @var \Flarum\Core\User
*/
public $actor;
/**
* The attributes to update on the discussion.
*
* @var array
*/
public $data;
/**
* @param integer $discussionId The ID of the discussion to edit.
* @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)
{
$this->discussionId = $discussionId;
$this->actor = $actor;
$this->data = $data;
}
}

View File

@@ -0,0 +1,79 @@
<?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\DiscussionWillBeSaved;
use Illuminate\Contracts\Events\Dispatcher;
class EditDiscussionHandler
{
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 EditDiscussion $command
* @return \Flarum\Core\Discussion
* @throws PermissionDeniedException
*/
public function handle(EditDiscussion $command)
{
$actor = $command->actor;
$data = $command->data;
$attributes = array_get($data, 'attributes', []);
$discussion = $this->discussions->findOrFail($command->discussionId, $actor);
if (isset($attributes['title'])) {
$this->assertCan($actor, 'rename', $discussion);
$discussion->rename($attributes['title']);
}
if (isset($attributes['isHidden'])) {
$this->assertCan($actor, 'hide', $discussion);
if ($attributes['isHidden']) {
$discussion->hide($actor);
} else {
$discussion->restore();
}
}
$this->events->fire(
new DiscussionWillBeSaved($discussion, $actor, $data)
);
$discussion->save();
$this->dispatchEventsFor($discussion, $actor);
return $discussion;
}
}

View File

@@ -0,0 +1,50 @@
<?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\Group;
use Flarum\Core\User;
class EditGroup
{
/**
* The ID of the group to edit.
*
* @var int
*/
public $groupId;
/**
* The user performing the action.
*
* @var User
*/
public $actor;
/**
* The attributes to update on the post.
*
* @var array
*/
public $data;
/**
* @param int $groupId The ID of the group to edit.
* @param User $actor The user performing the action.
* @param array $data The attributes to update on the post.
*/
public function __construct($groupId, User $actor, array $data)
{
$this->groupId = $groupId;
$this->actor = $actor;
$this->data = $data;
}
}

View File

@@ -0,0 +1,79 @@
<?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\Group;
use Flarum\Core\Repository\GroupRepository;
use Flarum\Event\GroupWillBeSaved;
use Flarum\Core\Support\DispatchEventsTrait;
use Illuminate\Contracts\Events\Dispatcher;
class EditGroupHandler
{
use DispatchEventsTrait;
use AssertPermissionTrait;
/**
* @var GroupRepository
*/
protected $groups;
/**
* @param Dispatcher $events
* @param GroupRepository $groups
*/
public function __construct(Dispatcher $events, GroupRepository $groups)
{
$this->events = $events;
$this->groups = $groups;
}
/**
* @param EditGroup $command
* @return Group
* @throws PermissionDeniedException
*/
public function handle(EditGroup $command)
{
$actor = $command->actor;
$data = $command->data;
$group = $this->groups->findOrFail($command->groupId, $actor);
$this->assertCan($actor, 'edit', $group);
$attributes = array_get($data, 'attributes', []);
if (isset($attributes['nameSingular']) && isset($attributes['namePlural'])) {
$group->rename($attributes['nameSingular'], $attributes['namePlural']);
}
if (isset($attributes['color'])) {
$group->color = $attributes['color'];
}
if (isset($attributes['icon'])) {
$group->icon = $attributes['icon'];
}
$this->events->fire(
new GroupWillBeSaved($group, $actor, $data)
);
$group->save();
$this->dispatchEventsFor($group, $actor);
return $group;
}
}

View File

@@ -0,0 +1,49 @@
<?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\User;
class EditPost
{
/**
* The ID of the post to edit.
*
* @var int
*/
public $postId;
/**
* The user performing the action.
*
* @var User
*/
public $actor;
/**
* The attributes to update on the post.
*
* @var array
*/
public $data;
/**
* @param int $postId The ID of the post to edit.
* @param User $actor The user performing the action.
* @param array $data The attributes to update on the post.
*/
public function __construct($postId, User $actor, array $data)
{
$this->postId = $postId;
$this->actor = $actor;
$this->data = $data;
}
}

View File

@@ -0,0 +1,82 @@
<?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\Repository\PostRepository;
use Flarum\Event\PostWillBeSaved;
use Flarum\Core\Support\DispatchEventsTrait;
use Flarum\Core\Post\CommentPost;
use Illuminate\Contracts\Events\Dispatcher;
class EditPostHandler
{
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 EditPost $command
* @return \Flarum\Core\Post
* @throws \Flarum\Core\Exception\PermissionDeniedException
*/
public function handle(EditPost $command)
{
$actor = $command->actor;
$data = $command->data;
$post = $this->posts->findOrFail($command->postId, $actor);
if ($post instanceof CommentPost) {
$attributes = array_get($data, 'attributes', []);
if (isset($attributes['content'])) {
$this->assertCan($actor, 'edit', $post);
$post->revise($attributes['content'], $actor);
}
if (isset($attributes['isHidden'])) {
$this->assertCan($actor, 'edit', $post);
if ($attributes['isHidden']) {
$post->hide($actor);
} else {
$post->restore();
}
}
}
$this->events->fire(
new PostWillBeSaved($post, $actor, $data)
);
$post->save();
$this->dispatchEventsFor($post, $actor);
return $post;
}
}

View File

@@ -0,0 +1,49 @@
<?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\User;
class EditUser
{
/**
* The ID of the user to edit.
*
* @var int
*/
public $userId;
/**
* The user performing the action.
*
* @var User
*/
public $actor;
/**
* The attributes to update on the post.
*
* @var array
*/
public $data;
/**
* @param int $userId The ID of the user to edit.
* @param User $actor The user performing the action.
* @param array $data The attributes to update on the post.
*/
public function __construct($userId, User $actor, array $data)
{
$this->userId = $userId;
$this->actor = $actor;
$this->data = $data;
}
}

View File

@@ -0,0 +1,128 @@
<?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\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 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 EditUser $command
* @return User
* @throws \Flarum\Core\Exception\PermissionDeniedException
*/
public function handle(EditUser $command)
{
$actor = $command->actor;
$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'])) {
$this->assertPermission($canEdit);
$user->rename($attributes['username']);
}
if (isset($attributes['email'])) {
if ($isSelf) {
$user->requestEmailChange($attributes['email']);
} else {
$this->assertPermission($canEdit);
$user->changeEmail($attributes['email']);
}
}
if (isset($attributes['password'])) {
$this->assertPermission($canEdit);
$user->changePassword($attributes['password']);
}
if (isset($attributes['bio'])) {
if (! $isSelf) {
$this->assertPermission($canEdit);
}
$user->changeBio($attributes['bio']);
}
if (! empty($attributes['readTime'])) {
$this->assertPermission($isSelf);
$user->markAllAsRead();
}
if (! empty($attributes['preferences'])) {
$this->assertPermission($isSelf);
foreach ($attributes['preferences'] as $k => $v) {
$user->setPreference($k, $v);
}
}
if (isset($relationships['groups']['data']) && is_array($relationships['groups']['data'])) {
$this->assertPermission($canEdit);
$newGroupIds = [];
foreach ($relationships['groups']['data'] as $group) {
if ($id = array_get($group, 'id')) {
$newGroupIds[] = $id;
}
}
$user->raise(
new UserGroupsWereChanged($user, $user->groups()->get()->all())
);
$user->afterSave(function (User $user) use ($newGroupIds) {
$user->groups()->sync($newGroupIds);
});
}
$this->events->fire(
new UserWillBeSaved($user, $actor, $data)
);
$user->save();
$this->dispatchEventsFor($user, $actor);
return $user;
}
}

View File

@@ -0,0 +1,49 @@
<?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\User;
class PostReply
{
/**
* The ID of the discussion to post the reply to.
*
* @var int
*/
public $discussionId;
/**
* The user who is performing the action.
*
* @var User
*/
public $actor;
/**
* The attributes to assign to the new post.
*
* @var array
*/
public $data;
/**
* @param int $discussionId The ID of the discussion to post the reply to.
* @param User $actor The user who is performing the action.
* @param array $data The attributes to assign to the new post.
*/
public function __construct($discussionId, User $actor, array $data)
{
$this->discussionId = $discussionId;
$this->actor = $actor;
$this->data = $data;
}
}

View File

@@ -0,0 +1,90 @@
<?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\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 DispatchEventsTrait;
use AssertPermissionTrait;
/**
* @var DiscussionRepository
*/
protected $discussions;
/**
* @var NotificationSyncer
*/
protected $notifications;
/**
* @param Dispatcher $events
* @param DiscussionRepository $discussions
* @param NotificationSyncer $notifications
*/
public function __construct(
Dispatcher $events,
DiscussionRepository $discussions,
NotificationSyncer $notifications
) {
$this->events = $events;
$this->discussions = $discussions;
$this->notifications = $notifications;
}
/**
* @param PostReply $command
* @return CommentPost
* @throws \Flarum\Core\Exception\PermissionDeniedException
*/
public function handle(PostReply $command)
{
$actor = $command->actor;
// Make sure the user has permission to reply to this discussion. First,
// make sure the discussion exists and that the user has permission to
// view it; if not, fail with a ModelNotFound exception so we don't give
// away the existence of the discussion. If the user is allowed to view
// it, check if they have permission to reply.
$discussion = $this->discussions->findOrFail($command->discussionId, $actor);
$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(
$discussion->id,
array_get($command->data, 'attributes.content'),
$actor->id
);
$this->events->fire(
new PostWillBeSaved($post, $actor, $command->data)
);
$post->save();
$this->notifications->onePerUser(function () use ($post, $actor) {
$this->dispatchEventsFor($post, $actor);
});
return $post;
}
}

View File

@@ -0,0 +1,31 @@
<?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\User;
class ReadAllNotifications
{
/**
* The user performing the action.
*
* @var User
*/
public $actor;
/**
* @param User $actor The user performing the action.
*/
public function __construct(User $actor)
{
$this->actor = $actor;
}
}

View File

@@ -0,0 +1,46 @@
<?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\Notification;
use Flarum\Core\Repository\NotificationRepository;
class ReadAllNotificationsHandler
{
use AssertPermissionTrait;
/**
* @var NotificationRepository
*/
protected $notifications;
/**
* @param NotificationRepository $notifications
*/
public function __construct(NotificationRepository $notifications)
{
$this->notifications = $notifications;
}
/**
* @param ReadAllNotifications $command
* @throws \Flarum\Core\Exception\PermissionDeniedException
*/
public function handle(ReadAllNotifications $command)
{
$actor = $command->actor;
$this->assertRegistered($actor);
$this->notifications->markAllAsRead($actor);
}
}

View File

@@ -0,0 +1,49 @@
<?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\User;
class ReadDiscussion
{
/**
* The ID of the discussion to mark as read.
*
* @var integer
*/
public $discussionId;
/**
* The user to mark the discussion as read for.
*
* @var User
*/
public $actor;
/**
* The number of the post to mark as read.
*
* @var integer
*/
public $readNumber;
/**
* @param integer $discussionId The ID of the discussion to mark as read.
* @param User $actor The user to mark the discussion as read for.
* @param integer $readNumber The number of the post to mark as read.
*/
public function __construct($discussionId, User $actor, $readNumber)
{
$this->discussionId = $discussionId;
$this->actor = $actor;
$this->readNumber = $readNumber;
}
}

View File

@@ -0,0 +1,65 @@
<?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\Repository\DiscussionRepository;
use Flarum\Core\Support\DispatchEventsTrait;
use Flarum\Event\DiscussionStateWillBeSaved;
use Illuminate\Contracts\Events\Dispatcher;
class ReadDiscussionHandler
{
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 ReadDiscussion $command
* @return \Flarum\Core\DiscussionState
* @throws \Flarum\Core\Exception\PermissionDeniedException
*/
public function handle(ReadDiscussion $command)
{
$actor = $command->actor;
$this->assertRegistered($actor);
$discussion = $this->discussions->findOrFail($command->discussionId, $actor);
$state = $discussion->stateFor($actor);
$state->read($command->readNumber);
$this->events->fire(
new DiscussionStateWillBeSaved($state)
);
$state->save();
$this->dispatchEventsFor($state);
return $state;
}
}

View File

@@ -0,0 +1,40 @@
<?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\User;
class ReadNotification
{
/**
* The ID of the notification to mark as read.
*
* @var int
*/
public $notificationId;
/**
* The user performing the action.
*
* @var User
*/
public $actor;
/**
* @param int $notificationId The ID of the notification to mark as read.
* @param User $actor The user performing the action.
*/
public function __construct($notificationId, User $actor)
{
$this->notificationId = $notificationId;
$this->actor = $actor;
}
}

View File

@@ -0,0 +1,44 @@
<?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\Notification;
class ReadNotificationHandler
{
use AssertPermissionTrait;
/**
* @param ReadNotification $command
* @return \Flarum\Core\Notification
* @throws \Flarum\Core\Exception\PermissionDeniedException
*/
public function handle(ReadNotification $command)
{
$actor = $command->actor;
$this->assertRegistered($actor);
$notification = Notification::where('user_id', $actor->id)->findOrFail($command->notificationId);
Notification::where([
'user_id' => $actor->id,
'type' => $notification->type,
'subject_id' => $notification->subject_id
])
->update(['is_read' => true]);
$notification->is_read = true;
return $notification;
}
}

View File

@@ -0,0 +1,40 @@
<?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\User;
class RegisterUser
{
/**
* The user performing the action.
*
* @var User
*/
public $actor;
/**
* The attributes of the new user.
*
* @var array
*/
public $data;
/**
* @param User $actor The user performing the action.
* @param array $data The attributes of the new user.
*/
public function __construct(User $actor, array $data)
{
$this->actor = $actor;
$this->data = $data;
}
}

View File

@@ -0,0 +1,101 @@
<?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\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 DispatchEventsTrait;
use AssertPermissionTrait;
/**
* @var SettingsRepository
*/
protected $settings;
/**
* @param Dispatcher $events
* @param 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\Exception\InvalidConfirmationTokenException if an
* email confirmation token is provided but is invalid.
* @return User
*/
public function handle(RegisterUser $command)
{
$actor = $command->actor;
$data = $command->data;
if (! $this->settings->get('allow_sign_up')) {
$this->assertAdmin($actor);
}
$username = array_get($data, 'attributes.username');
$email = array_get($data, 'attributes.email');
$password = array_get($data, 'attributes.password');
// If a valid authentication token was provided as an attribute,
// then we won't require the user to choose a password.
if (isset($data['attributes']['token'])) {
$token = AuthToken::validOrFail($data['attributes']['token']);
$password = $password ?: str_random(20);
}
$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
// includes an email address, then we will activate the user's account
// from the get-go.
if (isset($token)) {
foreach ($token->payload as $k => $v) {
$user->$k = $v;
}
if (isset($token->payload['email'])) {
$user->activate();
}
}
$this->events->fire(
new UserWillBeSaved($user, $actor, $data)
);
$user->save();
if (isset($token)) {
$token->delete();
}
$this->dispatchEventsFor($user, $actor);
return $user;
}
}

View File

@@ -0,0 +1,29 @@
<?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;
class RequestPasswordReset
{
/**
* The email of the user to request a password reset for.
*
* @var string
*/
public $email;
/**
* @param string $email The email of the user to request a password reset for.
*/
public function __construct($email)
{
$this->email = $email;
}
}

View File

@@ -0,0 +1,87 @@
<?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\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;
use Flarum\Core;
use Flarum\Forum\UrlGenerator;
class RequestPasswordResetHandler
{
/**
* @var UserRepository
*/
protected $users;
/**
* @var SettingsRepository
*/
protected $settings;
/**
* @var Mailer
*/
protected $mailer;
/**
* @var UrlGenerator
*/
protected $url;
/**
* @param UserRepository $users
* @param SettingsRepository $settings
* @param Mailer $mailer
* @param UrlGenerator $url
*/
public function __construct(UserRepository $users, SettingsRepository $settings, Mailer $mailer, UrlGenerator $url)
{
$this->users = $users;
$this->settings = $settings;
$this->mailer = $mailer;
$this->url = $url;
}
/**
* @param RequestPasswordReset $command
* @return \Flarum\Core\User
* @throws ModelNotFoundException
*/
public function handle(RequestPasswordReset $command)
{
$user = $this->users->findByEmail($command->email);
if (! $user) {
throw new ModelNotFoundException;
}
$token = PasswordToken::generate($user->id);
$token->save();
$data = [
'username' => $user->username,
'url' => $this->url->toRoute('resetPassword', ['token' => $token->id]),
'forumTitle' => $this->settings->get('forum_title'),
];
$this->mailer->send(['text' => 'flarum::emails.resetPassword'], $data, function (Message $message) use ($user) {
$message->to($user->email);
$message->subject('Reset Your Password');
});
return $user;
}
}

View File

@@ -0,0 +1,40 @@
<?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\User;
class StartDiscussion
{
/**
* The user authoring the discussion.
*
* @var User
*/
public $actor;
/**
* The discussion attributes.
*
* @var array
*/
public $data;
/**
* @param User $actor The user authoring the discussion.
* @param array $data The discussion attributes.
*/
public function __construct(User $actor, array $data)
{
$this->actor = $actor;
$this->data = $data;
}
}

View File

@@ -0,0 +1,93 @@
<?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 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 DispatchEventsTrait;
use AssertPermissionTrait;
/**
* @var BusDispatcher
*/
protected $bus;
/**
* @param EventDispatcher $events
* @param BusDispatcher $bus
* @internal param Forum $forum
*/
public function __construct(EventDispatcher $events, BusDispatcher $bus)
{
$this->events = $events;
$this->bus = $bus;
}
/**
* @param StartDiscussion $command
* @return mixed
* @throws Exception
*/
public function handle(StartDiscussion $command)
{
$actor = $command->actor;
$data = $command->data;
$this->assertCan($actor, 'startDiscussion');
// Create a new Discussion entity, persist it, and dispatch domain
// events. Before persistance, though, fire an event to give plugins
// an opportunity to alter the discussion entity based on data in the
// command they may have passed through in the controller.
$discussion = Discussion::start(
array_get($data, 'attributes.title'),
$actor
);
$this->events->fire(
new DiscussionWillBeSaved($discussion, $actor, $data)
);
$discussion->save();
// Now that the discussion has been created, we can add the first post.
// We will do this by running the PostReply command.
try {
$post = $this->bus->dispatch(
new PostReply($discussion->id, $actor, $data)
);
} catch (Exception $e) {
$discussion->delete();
throw $e;
}
// Before we dispatch events, refresh our discussion instance's
// attributes as posting the reply will have changed some of them (e.g.
// last_time.)
$discussion->setRawAttributes($post->discussion->getAttributes(), true);
$discussion->setStartPost($post);
$this->dispatchEventsFor($discussion, $actor);
$discussion->save();
return $discussion;
}
}

View File

@@ -0,0 +1,50 @@
<?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\User;
use Psr\Http\Message\UploadedFileInterface;
class UploadAvatar
{
/**
* The ID of the user to upload the avatar for.
*
* @var int
*/
public $userId;
/**
* The avatar file to upload.
*
* @var UploadedFileInterface
*/
public $file;
/**
* The user performing the action.
*
* @var User
*/
public $actor;
/**
* @param int $userId The ID of the user to upload the avatar for.
* @param UploadedFileInterface $file The avatar file to upload.
* @param User $actor The user performing the action.
*/
public function __construct($userId, UploadedFileInterface $file, User $actor)
{
$this->userId = $userId;
$this->file = $file;
$this->actor = $actor;
}
}

View File

@@ -0,0 +1,98 @@
<?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\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;
use League\Flysystem\FilesystemInterface;
use League\Flysystem\MountManager;
use Intervention\Image\ImageManager;
class UploadAvatarHandler
{
use DispatchEventsTrait;
use AssertPermissionTrait;
/**
* @var UserRepository
*/
protected $users;
/**
* @var FilesystemInterface
*/
protected $uploadDir;
/**
* @param Dispatcher $events
* @param UserRepository $users
* @param 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\User
* @throws \Flarum\Core\Exception\PermissionDeniedException
*/
public function handle(UploadAvatar $command)
{
$actor = $command->actor;
$user = $this->users->findOrFail($command->userId);
if ($actor->id !== $user->id) {
$this->assertCan($actor, 'edit', $user);
}
$tmpFile = tempnam(sys_get_temp_dir(), 'avatar');
$command->file->moveTo($tmpFile);
$manager = new ImageManager;
$manager->make($tmpFile)->fit(100, 100)->save();
$this->events->fire(
new AvatarWillBeSaved($user, $actor, $tmpFile)
);
$mount = new MountManager([
'source' => new Filesystem(new Local(pathinfo($tmpFile, PATHINFO_DIRNAME))),
'target' => $this->uploadDir,
]);
if ($user->avatar_path && $mount->has($file = "target://$user->avatar_path")) {
$mount->delete($file);
}
$uploadName = Str::lower(Str::quickRandom()) . '.jpg';
$user->changeAvatarPath($uploadName);
$mount->move("source://".pathinfo($tmpFile, PATHINFO_BASENAME), "target://$uploadName");
$user->save();
$this->dispatchEventsFor($user, $actor);
return $user;
}
}