1
0
mirror of https://github.com/flarum/core.git synced 2025-08-05 07:57:46 +02:00

chore: delete dead code

This commit is contained in:
Sami Mazouz
2024-02-10 16:05:31 +01:00
parent 5e1f97141b
commit 4e3b5f7c2c
41 changed files with 0 additions and 2281 deletions

View File

@@ -1,62 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Api\Controller;
use Flarum\Api\Serializer\DiscussionSerializer;
use Flarum\Discussion\Command\ReadDiscussion;
use Flarum\Discussion\Command\StartDiscussion;
use Flarum\Discussion\Discussion;
use Flarum\Http\RequestUtil;
use Illuminate\Contracts\Bus\Dispatcher;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Arr;
use Psr\Http\Message\ServerRequestInterface;
use Tobscure\JsonApi\Document;
class CreateDiscussionController extends AbstractCreateController
{
public ?string $serializer = DiscussionSerializer::class;
public array $include = [
'posts',
'user',
'lastPostedUser',
'firstPost',
'lastPost'
];
public function __construct(
protected Dispatcher $bus
) {
}
protected function data(ServerRequestInterface $request, Document $document): Discussion
{
$actor = RequestUtil::getActor($request);
$ipAddress = $request->getAttribute('ipAddress');
$discussion = $this->bus->dispatch(
new StartDiscussion($actor, Arr::get($request->getParsedBody(), 'data', []), $ipAddress)
);
// After creating the discussion, we assume that the user has seen all
// the posts in the discussion; thus, we will mark the discussion
// as read if they are logged in.
if ($actor->exists) {
$this->bus->dispatch(
new ReadDiscussion($discussion->id, $actor, 1)
);
}
$this->loadRelations(new Collection([$discussion]), $this->extractInclude($request), $request);
return $discussion;
}
}

View File

@@ -1,66 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Api\Controller;
use Flarum\Api\Serializer\PostSerializer;
use Flarum\Discussion\Command\ReadDiscussion;
use Flarum\Http\RequestUtil;
use Flarum\Post\Command\PostReply;
use Flarum\Post\CommentPost;
use Illuminate\Contracts\Bus\Dispatcher;
use Illuminate\Support\Arr;
use Psr\Http\Message\ServerRequestInterface;
use Tobscure\JsonApi\Document;
class CreatePostController extends AbstractCreateController
{
public ?string $serializer = PostSerializer::class;
public array $include = [
'user',
'discussion',
'discussion.posts',
'discussion.lastPostedUser'
];
public function __construct(
protected Dispatcher $bus
) {
}
protected function data(ServerRequestInterface $request, Document $document): CommentPost
{
$actor = RequestUtil::getActor($request);
$data = Arr::get($request->getParsedBody(), 'data', []);
$discussionId = (int) Arr::get($data, 'relationships.discussion.data.id');
$ipAddress = $request->getAttribute('ipAddress');
/** @var CommentPost $post */
$post = $this->bus->dispatch(
new PostReply($discussionId, $actor, $data, $ipAddress)
);
// After replying, we assume that the user has seen all of the posts
// in the discussion; thus, we will mark the discussion as read if
// they are logged in.
if ($actor->exists) {
$this->bus->dispatch(
new ReadDiscussion($discussionId, $actor, $post->number)
);
}
$discussion = $post->discussion;
$discussion->setRelation('posts', $discussion->posts()->whereVisibleTo($actor)->orderBy('created_at')->pluck('id'));
$this->loadRelations($post->newCollection([$post]), $this->extractInclude($request), $request);
return $post;
}
}

View File

@@ -1,36 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Api\Controller;
use Flarum\Api\Serializer\CurrentUserSerializer;
use Flarum\Http\RequestUtil;
use Flarum\User\Command\RegisterUser;
use Flarum\User\User;
use Illuminate\Contracts\Bus\Dispatcher;
use Illuminate\Support\Arr;
use Psr\Http\Message\ServerRequestInterface;
use Tobscure\JsonApi\Document;
class CreateUserController extends AbstractCreateController
{
public ?string $serializer = CurrentUserSerializer::class;
public function __construct(
protected Dispatcher $bus
) {
}
protected function data(ServerRequestInterface $request, Document $document): User
{
return $this->bus->dispatch(
new RegisterUser(RequestUtil::getActor($request), Arr::get($request->getParsedBody(), 'data', []))
);
}
}

View File

@@ -1,35 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Api\Controller;
use Flarum\Discussion\Command\DeleteDiscussion;
use Flarum\Http\RequestUtil;
use Illuminate\Contracts\Bus\Dispatcher;
use Illuminate\Support\Arr;
use Psr\Http\Message\ServerRequestInterface;
class DeleteDiscussionController extends AbstractDeleteController
{
public function __construct(
protected Dispatcher $bus
) {
}
protected function delete(ServerRequestInterface $request): void
{
$id = Arr::get($request->getQueryParams(), 'id');
$actor = RequestUtil::getActor($request);
$input = $request->getParsedBody();
$this->bus->dispatch(
new DeleteDiscussion($id, $actor, $input)
);
}
}

View File

@@ -1,31 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Api\Controller;
use Flarum\Http\RequestUtil;
use Flarum\Post\Command\DeletePost;
use Illuminate\Contracts\Bus\Dispatcher;
use Illuminate\Support\Arr;
use Psr\Http\Message\ServerRequestInterface;
class DeletePostController extends AbstractDeleteController
{
public function __construct(
protected Dispatcher $bus
) {
}
protected function delete(ServerRequestInterface $request): void
{
$this->bus->dispatch(
new DeletePost(Arr::get($request->getQueryParams(), 'id'), RequestUtil::getActor($request))
);
}
}

View File

@@ -1,31 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Api\Controller;
use Flarum\Http\RequestUtil;
use Flarum\User\Command\DeleteUser;
use Illuminate\Contracts\Bus\Dispatcher;
use Illuminate\Support\Arr;
use Psr\Http\Message\ServerRequestInterface;
class DeleteUserController extends AbstractDeleteController
{
public function __construct(
protected Dispatcher $bus
) {
}
protected function delete(ServerRequestInterface $request): void
{
$this->bus->dispatch(
new DeleteUser(Arr::get($request->getQueryParams(), 'id'), RequestUtil::getActor($request))
);
}
}

View File

@@ -1,99 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Api\Controller;
use Flarum\Api\Serializer\DiscussionSerializer;
use Flarum\Discussion\Discussion;
use Flarum\Http\RequestUtil;
use Flarum\Http\UrlGenerator;
use Flarum\Search\SearchCriteria;
use Flarum\Search\SearchManager;
use Psr\Http\Message\ServerRequestInterface;
use Tobscure\JsonApi\Document;
class ListDiscussionsController extends AbstractListController
{
public ?string $serializer = DiscussionSerializer::class;
public array $include = [
'user',
'lastPostedUser',
'mostRelevantPost',
'mostRelevantPost.user'
];
public array $optionalInclude = [
'firstPost',
'lastPost'
];
public ?array $sort = ['lastPostedAt' => 'desc'];
public array $sortFields = ['lastPostedAt', 'commentCount', 'createdAt'];
public function __construct(
protected SearchManager $search,
protected UrlGenerator $url
) {
}
protected function data(ServerRequestInterface $request, Document $document): iterable
{
$actor = RequestUtil::getActor($request);
$filters = $this->extractFilter($request);
$sort = $this->extractSort($request);
$sortIsDefault = $this->sortIsDefault($request);
$limit = $this->extractLimit($request);
$offset = $this->extractOffset($request);
$include = array_merge($this->extractInclude($request), ['state']);
$results = $this->search->query(
Discussion::class,
new SearchCriteria($actor, $filters, $limit, $offset, $sort, $sortIsDefault)
);
$this->addPaginationData(
$document,
$request,
$this->url->to('api')->route('discussions.index'),
$results->areMoreResults() ? null : 0
);
Discussion::setStateUser($actor);
// Eager load groups for use in the policies (isAdmin check)
if (in_array('mostRelevantPost.user', $include)) {
$include[] = 'mostRelevantPost.user.groups';
// If the first level of the relationship wasn't explicitly included,
// add it so the code below can look for it
if (! in_array('mostRelevantPost', $include)) {
$include[] = 'mostRelevantPost';
}
}
$results = $results->getResults();
$this->loadRelations($results, $include, $request);
if ($relations = array_intersect($include, ['firstPost', 'lastPost', 'mostRelevantPost'])) {
foreach ($results as $discussion) {
foreach ($relations as $relation) {
if ($discussion->$relation) {
$discussion->$relation->discussion = $discussion;
}
}
}
}
return $results;
}
}

View File

@@ -1,100 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Api\Controller;
use Flarum\Api\Serializer\NotificationSerializer;
use Flarum\Discussion\Discussion;
use Flarum\Http\RequestUtil;
use Flarum\Http\UrlGenerator;
use Flarum\Notification\NotificationRepository;
use Psr\Http\Message\ServerRequestInterface;
use Tobscure\JsonApi\Document;
class ListNotificationsController extends AbstractListController
{
public ?string $serializer = NotificationSerializer::class;
public array $include = [
'fromUser',
'subject',
'subject.discussion'
];
public function __construct(
protected NotificationRepository $notifications,
protected UrlGenerator $url
) {
}
protected function data(ServerRequestInterface $request, Document $document): iterable
{
$actor = RequestUtil::getActor($request);
$actor->assertRegistered();
$actor->markNotificationsAsRead()->save();
$limit = $this->extractLimit($request);
$offset = $this->extractOffset($request);
$include = $this->extractInclude($request);
if (! in_array('subject', $include)) {
$include[] = 'subject';
}
$notifications = $this->notifications->findByUser($actor, $limit + 1, $offset);
$this->loadRelations($notifications, array_diff($include, ['subject.discussion']), $request);
$notifications = $notifications->all();
$areMoreResults = false;
if (count($notifications) > $limit) {
array_pop($notifications);
$areMoreResults = true;
}
$this->addPaginationData(
$document,
$request,
$this->url->to('api')->route('notifications.index'),
$areMoreResults ? null : 0
);
if (in_array('subject.discussion', $include)) {
$this->loadSubjectDiscussions($notifications);
}
return $notifications;
}
/**
* @param \Flarum\Notification\Notification[] $notifications
*/
private function loadSubjectDiscussions(array $notifications): void
{
$ids = [];
foreach ($notifications as $notification) {
if ($notification->subject && ($discussionId = $notification->subject->getAttribute('discussion_id'))) {
$ids[] = $discussionId;
}
}
$discussions = Discussion::query()->find(array_unique($ids));
foreach ($notifications as $notification) {
if ($notification->subject && ($discussionId = $notification->subject->getAttribute('discussion_id'))) {
$notification->subject->setRelation('discussion', $discussions->find($discussionId));
}
}
}
}

View File

@@ -1,124 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Api\Controller;
use Flarum\Api\Serializer\PostSerializer;
use Flarum\Http\RequestUtil;
use Flarum\Http\UrlGenerator;
use Flarum\Post\Post;
use Flarum\Post\PostRepository;
use Flarum\Search\SearchCriteria;
use Flarum\Search\SearchManager;
use Illuminate\Support\Arr;
use Psr\Http\Message\ServerRequestInterface;
use Tobscure\JsonApi\Document;
use Tobscure\JsonApi\Exception\InvalidParameterException;
class ListPostsController extends AbstractListController
{
public ?string $serializer = PostSerializer::class;
public array $include = [
'user',
'user.groups',
'editedUser',
'hiddenUser',
'discussion'
];
public array $sortFields = ['number', 'createdAt'];
public function __construct(
protected SearchManager $search,
protected PostRepository $posts,
protected UrlGenerator $url
) {
}
protected function data(ServerRequestInterface $request, Document $document): iterable
{
$actor = RequestUtil::getActor($request);
$filters = $this->extractFilter($request);
$sort = $this->extractSort($request);
$sortIsDefault = $this->sortIsDefault($request);
$limit = $this->extractLimit($request);
$offset = $this->extractOffset($request);
$include = $this->extractInclude($request);
$results = $this->search->query(
Post::class,
new SearchCriteria($actor, $filters, $limit, $offset, $sort, $sortIsDefault)
);
$document->addPaginationLinks(
$this->url->to('api')->route('posts.index'),
$request->getQueryParams(),
$offset,
$limit,
$results->areMoreResults() ? null : 0
);
// Eager load discussion for use in the policies,
// eager loading does not affect the JSON response,
// the response only includes relations included in the request.
if (! in_array('discussion', $include)) {
$include[] = 'discussion';
}
if (in_array('user', $include)) {
$include[] = 'user.groups';
}
$results = $results->getResults();
$this->loadRelations($results, $include, $request);
return $results;
}
/**
* @link https://github.com/flarum/framework/pull/3506
*/
protected function extractSort(ServerRequestInterface $request): ?array
{
$sort = [];
foreach ((parent::extractSort($request) ?: []) as $field => $direction) {
$sort["posts.$field"] = $direction;
}
return $sort;
}
protected function extractOffset(ServerRequestInterface $request): int
{
$actor = RequestUtil::getActor($request);
$queryParams = $request->getQueryParams();
$sort = $this->extractSort($request);
$limit = $this->extractLimit($request);
$filter = $this->extractFilter($request);
if (($near = Arr::get($queryParams, 'page.near')) > 1) {
if (count($filter) > 1 || ! isset($filter['discussion']) || $sort) {
throw new InvalidParameterException(
'You can only use page[near] with filter[discussion] and the default sort order'
);
}
$offset = $this->posts->getIndexForNumber((int) $filter['discussion'], $near, $actor);
return max(0, $offset - $limit / 2);
}
return parent::extractOffset($request);
}
}

View File

@@ -1,81 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Api\Controller;
use Flarum\Api\Serializer\UserSerializer;
use Flarum\Http\RequestUtil;
use Flarum\Http\UrlGenerator;
use Flarum\Search\SearchCriteria;
use Flarum\Search\SearchManager;
use Flarum\User\User;
use Psr\Http\Message\ServerRequestInterface;
use Tobscure\JsonApi\Document;
class ListUsersController extends AbstractListController
{
public ?string $serializer = UserSerializer::class;
public array $include = ['groups'];
public array $sortFields = [
'username',
'commentCount',
'discussionCount',
'lastSeenAt',
'joinedAt'
];
public function __construct(
protected SearchManager $search,
protected UrlGenerator $url
) {
}
protected function data(ServerRequestInterface $request, Document $document): iterable
{
$actor = RequestUtil::getActor($request);
$actor->assertCan('searchUsers');
if (! $actor->hasPermission('user.viewLastSeenAt')) {
// If a user cannot see everyone's last online date, we prevent them from sorting by it
// Otherwise this sort field would defeat the privacy setting discloseOnline
// We use remove instead of add so that extensions can still completely disable the sort using the extender
$this->removeSortField('lastSeenAt');
}
$filters = $this->extractFilter($request);
$sort = $this->extractSort($request);
$sortIsDefault = $this->sortIsDefault($request);
$limit = $this->extractLimit($request);
$offset = $this->extractOffset($request);
$include = $this->extractInclude($request);
$results = $this->search->query(
User::class,
new SearchCriteria($actor, $filters, $limit, $offset, $sort, $sortIsDefault)
);
$document->addPaginationLinks(
$this->url->to('api')->route('users.index'),
$request->getQueryParams(),
$offset,
$limit,
$results->areMoreResults() ? null : 0
);
$results = $results->getResults();
$this->loadRelations($results, $include, $request);
return $results;
}
}

View File

@@ -1,178 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Api\Controller;
use Flarum\Api\Serializer\DiscussionSerializer;
use Flarum\Discussion\Discussion;
use Flarum\Discussion\DiscussionRepository;
use Flarum\Http\RequestUtil;
use Flarum\Http\SlugManager;
use Flarum\Post\Post;
use Flarum\Post\PostRepository;
use Flarum\User\User;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use Psr\Http\Message\ServerRequestInterface;
use Tobscure\JsonApi\Document;
class ShowDiscussionController extends AbstractShowController
{
public ?string $serializer = DiscussionSerializer::class;
public array $include = [
'user',
'posts',
'posts.discussion',
'posts.user',
'posts.user.groups',
'posts.editedUser',
'posts.hiddenUser'
];
public array $optionalInclude = [
'user',
'lastPostedUser',
'firstPost',
'lastPost'
];
public function __construct(
protected DiscussionRepository $discussions,
protected PostRepository $posts,
protected SlugManager $slugManager
) {
}
protected function data(ServerRequestInterface $request, Document $document): Discussion
{
$discussionId = Arr::get($request->getQueryParams(), 'id');
$actor = RequestUtil::getActor($request);
$include = $this->extractInclude($request);
if (Arr::get($request->getQueryParams(), 'bySlug', false)) {
$discussion = $this->slugManager->forResource(Discussion::class)->fromSlug($discussionId, $actor);
} else {
$discussion = $this->discussions->findOrFail($discussionId, $actor);
}
// If posts is included or a sub relation of post is included.
if (in_array('posts', $include) || Str::contains(implode(',', $include), 'posts.')) {
$postRelationships = $this->getPostRelationships($include);
$this->includePosts($discussion, $request, $postRelationships);
}
$this->loadRelations(new Collection([$discussion]), array_filter($include, function ($relationship) {
return ! Str::startsWith($relationship, 'posts');
}), $request);
return $discussion;
}
private function includePosts(Discussion $discussion, ServerRequestInterface $request, array $include): void
{
$actor = RequestUtil::getActor($request);
$limit = $this->extractLimit($request);
$offset = $this->getPostsOffset($request, $discussion, $limit);
$allPosts = $this->loadPostIds($discussion, $actor);
$loadedPosts = $this->loadPosts($discussion, $actor, $offset, $limit, $include, $request);
array_splice($allPosts, $offset, $limit, $loadedPosts);
$discussion->setRelation('posts', (new Post)->newCollection($allPosts));
}
private function loadPostIds(Discussion $discussion, User $actor): array
{
return $discussion->posts()->whereVisibleTo($actor)->orderBy('number')->pluck('id')->all();
}
private function getPostRelationships(array $include): array
{
$prefixLength = strlen($prefix = 'posts.');
$relationships = [];
foreach ($include as $relationship) {
if (substr($relationship, 0, $prefixLength) === $prefix) {
$relationships[] = substr($relationship, $prefixLength);
}
}
return $relationships;
}
private function getPostsOffset(ServerRequestInterface $request, Discussion $discussion, int $limit): int
{
$queryParams = $request->getQueryParams();
$actor = RequestUtil::getActor($request);
if (($near = Arr::get($queryParams, 'page.near')) > 1) {
$offset = $this->posts->getIndexForNumber($discussion->id, $near, $actor);
$offset = max(0, $offset - $limit / 2);
} else {
$offset = $this->extractOffset($request);
}
return $offset;
}
private function loadPosts(Discussion $discussion, User $actor, int $offset, int $limit, array $include, ServerRequestInterface $request): array
{
/** @var Builder $query */
$query = $discussion->posts()->whereVisibleTo($actor);
$query->orderBy('number')->skip($offset)->take($limit);
$posts = $query->get();
/** @var Post $post */
foreach ($posts as $post) {
$post->setRelation('discussion', $discussion);
}
$this->loadRelations($posts, $include, $request);
return $posts->all();
}
protected function getRelationsToLoad(Collection $models): array
{
$addedRelations = parent::getRelationsToLoad($models);
if ($models->first() instanceof Discussion) {
return $addedRelations;
}
return $this->getPostRelationships($addedRelations);
}
protected function getRelationCallablesToLoad(Collection $models): array
{
$addedCallableRelations = parent::getRelationCallablesToLoad($models);
if ($models->first() instanceof Discussion) {
return $addedCallableRelations;
}
$postCallableRelationships = $this->getPostRelationships(array_keys($addedCallableRelations));
$relationCallables = array_intersect_key($addedCallableRelations, array_flip(array_map(function ($relation) {
return "posts.$relation";
}, $postCallableRelationships)));
// remove posts. prefix from keys
return array_combine(array_map(function ($relation) {
return substr($relation, 6);
}, array_keys($relationCallables)), array_values($relationCallables));
}
}

View File

@@ -1,32 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Api\Controller;
use Flarum\Api\Endpoint\Show;
use Flarum\Api\JsonApi;
use Flarum\Api\Resource\ForumResource;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
class ShowForumController implements RequestHandlerInterface
{
public function __construct(
protected JsonApi $api
) {}
public function handle(ServerRequestInterface $request): ResponseInterface
{
return $this->api
->forResource(ForumResource::class)
->forEndpoint(Show::class)
->handle($request);
}
}

View File

@@ -1,48 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Api\Controller;
use Flarum\Api\Serializer\PostSerializer;
use Flarum\Http\RequestUtil;
use Flarum\Post\Post;
use Flarum\Post\PostRepository;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Arr;
use Psr\Http\Message\ServerRequestInterface;
use Tobscure\JsonApi\Document;
class ShowPostController extends AbstractShowController
{
public ?string $serializer = PostSerializer::class;
public array $include = [
'user',
'user.groups',
'editedUser',
'hiddenUser',
'discussion'
];
public function __construct(
protected PostRepository $posts
) {
}
protected function data(ServerRequestInterface $request, Document $document): Post
{
$post = $this->posts->findOrFail(Arr::get($request->getQueryParams(), 'id'), RequestUtil::getActor($request));
$include = $this->extractInclude($request);
$this->loadRelations(new Collection([$post]), $include, $request);
return $post;
}
}

View File

@@ -1,51 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Api\Controller;
use Flarum\Api\Serializer\CurrentUserSerializer;
use Flarum\Api\Serializer\UserSerializer;
use Flarum\Http\RequestUtil;
use Flarum\Http\SlugManager;
use Flarum\User\User;
use Flarum\User\UserRepository;
use Illuminate\Support\Arr;
use Psr\Http\Message\ServerRequestInterface;
use Tobscure\JsonApi\Document;
class ShowUserController extends AbstractShowController
{
public ?string $serializer = UserSerializer::class;
public array $include = ['groups'];
public function __construct(
protected SlugManager $slugManager,
protected UserRepository $users
) {
}
protected function data(ServerRequestInterface $request, Document $document): User
{
$id = Arr::get($request->getQueryParams(), 'id');
$actor = RequestUtil::getActor($request);
if (Arr::get($request->getQueryParams(), 'bySlug', false)) {
$user = $this->slugManager->forResource(User::class)->fromSlug($id, $actor);
} else {
$user = $this->users->findOrFail($id, $actor);
}
if ($actor->id === $user->id) {
$this->serializer = CurrentUserSerializer::class;
}
return $user;
}
}

View File

@@ -1,39 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Api\Controller;
use Flarum\Api\Serializer\NotificationSerializer;
use Flarum\Http\RequestUtil;
use Flarum\Notification\Command\ReadNotification;
use Flarum\Notification\Notification;
use Illuminate\Contracts\Bus\Dispatcher;
use Illuminate\Support\Arr;
use Psr\Http\Message\ServerRequestInterface;
use Tobscure\JsonApi\Document;
class UpdateNotificationController extends AbstractShowController
{
public ?string $serializer = NotificationSerializer::class;
public function __construct(
protected Dispatcher $bus
) {
}
protected function data(ServerRequestInterface $request, Document $document): Notification
{
$id = Arr::get($request->getQueryParams(), 'id');
$actor = RequestUtil::getActor($request);
return $this->bus->dispatch(
new ReadNotification($id, $actor)
);
}
}

View File

@@ -1,49 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Api\Controller;
use Flarum\Api\Serializer\PostSerializer;
use Flarum\Http\RequestUtil;
use Flarum\Post\Command\EditPost;
use Flarum\Post\Post;
use Illuminate\Contracts\Bus\Dispatcher;
use Illuminate\Support\Arr;
use Psr\Http\Message\ServerRequestInterface;
use Tobscure\JsonApi\Document;
class UpdatePostController extends AbstractShowController
{
public ?string $serializer = PostSerializer::class;
public array $include = [
'editedUser',
'discussion'
];
public function __construct(
protected Dispatcher $bus
) {
}
protected function data(ServerRequestInterface $request, Document $document): Post
{
$id = Arr::get($request->getQueryParams(), 'id');
$actor = RequestUtil::getActor($request);
$data = Arr::get($request->getParsedBody(), 'data', []);
$post = $this->bus->dispatch(
new EditPost($id, $actor, $data)
);
$this->loadRelations($post->newCollection([$post]), $this->extractInclude($request), $request);
return $post;
}
}

View File

@@ -1,58 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Api\Controller;
use Flarum\Api\Serializer\CurrentUserSerializer;
use Flarum\Api\Serializer\UserSerializer;
use Flarum\Http\RequestUtil;
use Flarum\User\Command\EditUser;
use Flarum\User\Exception\NotAuthenticatedException;
use Flarum\User\User;
use Illuminate\Contracts\Bus\Dispatcher;
use Illuminate\Support\Arr;
use Psr\Http\Message\ServerRequestInterface;
use Tobscure\JsonApi\Document;
class UpdateUserController extends AbstractShowController
{
public ?string $serializer = UserSerializer::class;
public array $include = ['groups'];
public function __construct(
protected Dispatcher $bus
) {
}
protected function data(ServerRequestInterface $request, Document $document): User
{
$id = Arr::get($request->getQueryParams(), 'id');
$actor = RequestUtil::getActor($request);
$data = Arr::get($request->getParsedBody(), 'data', []);
if ($actor->id == $id) {
$this->serializer = CurrentUserSerializer::class;
}
// Require the user's current password if they are attempting to change
// their own email address.
if (isset($data['attributes']['email']) && $actor->id == $id) {
$password = (string) Arr::get($request->getParsedBody(), 'meta.password');
if (! $actor->checkPassword($password)) {
throw new NotAuthenticatedException;
}
}
return $this->bus->dispatch(
new EditUser($id, $actor, $data)
);
}
}

View File

@@ -1,22 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Discussion\Command;
use Flarum\User\User;
class DeleteDiscussion
{
public function __construct(
public int $discussionId,
public User $actor,
public array $data = []
) {
}
}

View File

@@ -1,46 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Discussion\Command;
use Flarum\Discussion\Discussion;
use Flarum\Discussion\DiscussionRepository;
use Flarum\Discussion\Event\Deleting;
use Flarum\Foundation\DispatchEventsTrait;
use Illuminate\Contracts\Events\Dispatcher;
class DeleteDiscussionHandler
{
use DispatchEventsTrait;
public function __construct(
protected Dispatcher $events,
protected DiscussionRepository $discussions
) {
}
public function handle(DeleteDiscussion $command): Discussion
{
$actor = $command->actor;
$discussion = $this->discussions->findOrFail($command->discussionId, $actor);
$actor->assertCan('delete', $discussion);
$this->events->dispatch(
new Deleting($discussion, $actor, $command->data)
);
$discussion->delete();
$this->dispatchEventsFor($discussion, $actor);
return $discussion;
}
}

View File

@@ -1,22 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Discussion\Command;
use Flarum\User\User;
class EditDiscussion
{
public function __construct(
public int $discussionId,
public User $actor,
public array $data
) {
}
}

View File

@@ -1,67 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Discussion\Command;
use Flarum\Discussion\Discussion;
use Flarum\Discussion\DiscussionRepository;
use Flarum\Discussion\DiscussionValidator;
use Flarum\Discussion\Event\Saving;
use Flarum\Foundation\DispatchEventsTrait;
use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Support\Arr;
class EditDiscussionHandler
{
use DispatchEventsTrait;
public function __construct(
protected Dispatcher $events,
protected DiscussionRepository $discussions,
protected DiscussionValidator $validator
) {
}
public function handle(EditDiscussion $command): Discussion
{
$actor = $command->actor;
$data = $command->data;
$attributes = Arr::get($data, 'attributes', []);
$discussion = $this->discussions->findOrFail($command->discussionId, $actor);
if (isset($attributes['title'])) {
$actor->assertCan('rename', $discussion);
$discussion->rename($attributes['title']);
}
if (isset($attributes['isHidden'])) {
$actor->assertCan('hide', $discussion);
if ($attributes['isHidden']) {
$discussion->hide($actor);
} else {
$discussion->restore();
}
}
$this->events->dispatch(
new Saving($discussion, $actor, $data)
);
$this->validator->assertValid($discussion->getDirty());
$discussion->save();
$this->dispatchEventsFor($discussion, $actor);
return $discussion;
}
}

View File

@@ -1,22 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Discussion\Command;
use Flarum\User\User;
class StartDiscussion
{
public function __construct(
public User $actor,
public array $data,
public string $ipAddress
) {
}
}

View File

@@ -1,83 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Discussion\Command;
use Exception;
use Flarum\Discussion\Discussion;
use Flarum\Discussion\DiscussionValidator;
use Flarum\Discussion\Event\Saving;
use Flarum\Foundation\DispatchEventsTrait;
use Flarum\Post\Command\PostReply;
use Illuminate\Contracts\Bus\Dispatcher as BusDispatcher;
use Illuminate\Contracts\Events\Dispatcher as EventDispatcher;
use Illuminate\Support\Arr;
class StartDiscussionHandler
{
use DispatchEventsTrait;
public function __construct(
protected EventDispatcher $events,
protected BusDispatcher $bus,
protected DiscussionValidator $validator
) {
}
public function handle(StartDiscussion $command): Discussion
{
$actor = $command->actor;
$data = $command->data;
$ipAddress = $command->ipAddress;
$actor->assertCan('startDiscussion');
// Create a new Discussion entity, persist it, and dispatch domain
// events. Before persistence, 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(
Arr::get($data, 'attributes.title'),
$actor
);
$this->events->dispatch(
new Saving($discussion, $actor, $data)
);
$this->validator->assertValid($discussion->getAttributes());
$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, $ipAddress, true)
);
} 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->setFirstPost($post);
$discussion->setLastPost($post);
$this->dispatchEventsFor($discussion, $actor);
$discussion->save();
return $discussion;
}
}

View File

@@ -1,21 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Group\Command;
use Flarum\User\User;
class CreateGroup
{
public function __construct(
public User $actor,
public array $data
) {
}
}

View File

@@ -1,57 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Group\Command;
use Flarum\Foundation\DispatchEventsTrait;
use Flarum\Group\Event\Saving;
use Flarum\Group\Group;
use Flarum\Group\GroupValidator;
use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Support\Arr;
class CreateGroupHandler
{
use DispatchEventsTrait;
public function __construct(
protected Dispatcher $events,
protected GroupValidator $validator
) {
}
public function handle(CreateGroup $command): Group
{
$actor = $command->actor;
$data = $command->data;
$actor->assertRegistered();
$actor->assertCan('createGroup');
$group = Group::build(
Arr::get($data, 'attributes.nameSingular'),
Arr::get($data, 'attributes.namePlural'),
Arr::get($data, 'attributes.color'),
Arr::get($data, 'attributes.icon'),
Arr::get($data, 'attributes.isHidden', false)
);
$this->events->dispatch(
new Saving($group, $actor, $data)
);
$this->validator->assertValid($group->getAttributes());
$group->save();
$this->dispatchEventsFor($group, $actor);
return $group;
}
}

View File

@@ -1,22 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Group\Command;
use Flarum\User\User;
class DeleteGroup
{
public function __construct(
public int $groupId,
public User $actor,
public array $data = []
) {
}
}

View File

@@ -1,46 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Group\Command;
use Flarum\Foundation\DispatchEventsTrait;
use Flarum\Group\Event\Deleting;
use Flarum\Group\Group;
use Flarum\Group\GroupRepository;
use Illuminate\Contracts\Events\Dispatcher;
class DeleteGroupHandler
{
use DispatchEventsTrait;
public function __construct(
protected Dispatcher $events,
protected GroupRepository $groups
) {
}
public function handle(DeleteGroup $command): Group
{
$actor = $command->actor;
$group = $this->groups->findOrFail($command->groupId, $actor);
$actor->assertCan('delete', $group);
$this->events->dispatch(
new Deleting($group, $actor, $command->data)
);
$group->delete();
$this->dispatchEventsFor($group, $actor);
return $group;
}
}

View File

@@ -1,22 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Group\Command;
use Flarum\User\User;
class EditGroup
{
public function __construct(
public int $groupId,
public User $actor,
public array $data
) {
}
}

View File

@@ -1,70 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Group\Command;
use Flarum\Foundation\DispatchEventsTrait;
use Flarum\Group\Event\Saving;
use Flarum\Group\Group;
use Flarum\Group\GroupRepository;
use Flarum\Group\GroupValidator;
use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Support\Arr;
class EditGroupHandler
{
use DispatchEventsTrait;
public function __construct(
protected Dispatcher $events,
protected GroupRepository $groups,
protected GroupValidator $validator
) {
}
public function handle(EditGroup $command): Group
{
$actor = $command->actor;
$data = $command->data;
$group = $this->groups->findOrFail($command->groupId, $actor);
$actor->assertCan('edit', $group);
$attributes = Arr::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'];
}
if (isset($attributes['isHidden'])) {
$group->is_hidden = $attributes['isHidden'];
}
$this->events->dispatch(
new Saving($group, $actor, $data)
);
$this->validator->assertValid($group->getDirty());
$group->save();
$this->dispatchEventsFor($group, $actor);
return $group;
}
}

View File

@@ -1,22 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Post\Command;
use Flarum\User\User;
class DeletePost
{
public function __construct(
public int $postId,
public User $actor,
public array $data = []
) {
}
}

View File

@@ -1,46 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Post\Command;
use Flarum\Foundation\DispatchEventsTrait;
use Flarum\Post\Event\Deleting;
use Flarum\Post\Post;
use Flarum\Post\PostRepository;
use Illuminate\Contracts\Events\Dispatcher;
class DeletePostHandler
{
use DispatchEventsTrait;
public function __construct(
protected Dispatcher $events,
protected PostRepository $posts
) {
}
public function handle(DeletePost $command): Post
{
$actor = $command->actor;
$post = $this->posts->findOrFail($command->postId, $actor);
$actor->assertCan('delete', $post);
$this->events->dispatch(
new Deleting($post, $actor, $command->data)
);
$post->delete();
$this->dispatchEventsFor($post, $actor);
return $post;
}
}

View File

@@ -1,22 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Post\Command;
use Flarum\User\User;
class EditPost
{
public function __construct(
public int $postId,
public User $actor,
public array $data
) {
}
}

View File

@@ -1,71 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Post\Command;
use Flarum\Foundation\DispatchEventsTrait;
use Flarum\Post\CommentPost;
use Flarum\Post\Event\Saving;
use Flarum\Post\Post;
use Flarum\Post\PostRepository;
use Flarum\Post\PostValidator;
use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Support\Arr;
class EditPostHandler
{
use DispatchEventsTrait;
public function __construct(
protected Dispatcher $events,
protected PostRepository $posts,
protected PostValidator $validator
) {
}
public function handle(EditPost $command): Post|CommentPost
{
$actor = $command->actor;
$data = $command->data;
$post = $this->posts->findOrFail($command->postId, $actor);
if ($post instanceof CommentPost) {
$attributes = Arr::get($data, 'attributes', []);
if (isset($attributes['content'])) {
$actor->assertCan('edit', $post);
$post->revise($attributes['content'], $actor);
}
if (isset($attributes['isHidden'])) {
$actor->assertCan('hide', $post);
if ($attributes['isHidden']) {
$post->hide($actor);
} else {
$post->restore();
}
}
}
$this->events->dispatch(
new Saving($post, $actor, $data)
);
$this->validator->assertValid($post->getDirty());
$post->save();
$this->dispatchEventsFor($post, $actor);
return $post;
}
}

View File

@@ -1,24 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Post\Command;
use Flarum\User\User;
class PostReply
{
public function __construct(
public int $discussionId,
public User $actor,
public array $data,
public ?string $ipAddress = null,
public bool $isFirstPost = false
) {
}
}

View File

@@ -1,80 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Post\Command;
use Carbon\Carbon;
use Flarum\Discussion\DiscussionRepository;
use Flarum\Foundation\DispatchEventsTrait;
use Flarum\Notification\NotificationSyncer;
use Flarum\Post\CommentPost;
use Flarum\Post\Event\Saving;
use Flarum\Post\PostValidator;
use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Support\Arr;
class PostReplyHandler
{
use DispatchEventsTrait;
public function __construct(
protected Dispatcher $events,
protected DiscussionRepository $discussions,
protected NotificationSyncer $notifications,
protected PostValidator $validator
) {
}
public function handle(PostReply $command): CommentPost
{
$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);
// If this is the first post in the discussion, it's technically not a
// "reply", so we won't check for that permission.
if (! $command->isFirstPost) {
$actor->assertCan('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,
Arr::get($command->data, 'attributes.content'),
$actor->id,
$command->ipAddress,
$command->actor,
);
if ($actor->isAdmin() && ($time = Arr::get($command->data, 'attributes.createdAt'))) {
$post->created_at = new Carbon($time);
}
$this->events->dispatch(
new Saving($post, $actor, $command->data)
);
$this->validator->assertValid($post->getAttributes());
$post->save();
$this->notifications->onePerUser(function () use ($post, $actor) {
$this->dispatchEventsFor($post, $actor);
});
return $post;
}
}

View File

@@ -1,22 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\User\Command;
use Flarum\User\User;
class DeleteUser
{
public function __construct(
public int $userId,
public User $actor,
public array $data = []
) {
}
}

View File

@@ -1,49 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\User\Command;
use Flarum\Foundation\DispatchEventsTrait;
use Flarum\User\Event\Deleting;
use Flarum\User\Exception\PermissionDeniedException;
use Flarum\User\User;
use Flarum\User\UserRepository;
use Illuminate\Contracts\Events\Dispatcher;
class DeleteUserHandler
{
use DispatchEventsTrait;
public function __construct(
protected Dispatcher $events,
protected UserRepository $users
) {
}
/**
* @throws PermissionDeniedException
*/
public function handle(DeleteUser $command): User
{
$actor = $command->actor;
$user = $this->users->findOrFail($command->userId, $actor);
$actor->assertCan('delete', $user);
$this->events->dispatch(
new Deleting($user, $actor, $command->data)
);
$user->delete();
$this->dispatchEventsFor($user, $actor);
return $user;
}
}

View File

@@ -1,22 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\User\Command;
use Flarum\User\User;
class EditUser
{
public function __construct(
public int $userId,
public User $actor,
public array $data
) {
}
}

View File

@@ -1,128 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\User\Command;
use Flarum\Foundation\DispatchEventsTrait;
use Flarum\User\Event\GroupsChanged;
use Flarum\User\Event\Saving;
use Flarum\User\User;
use Flarum\User\UserRepository;
use Flarum\User\UserValidator;
use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Support\Arr;
class EditUserHandler
{
use DispatchEventsTrait;
public function __construct(
protected Dispatcher $events,
protected UserRepository $users,
protected UserValidator $validator
) {
}
public function handle(EditUser $command): User
{
$actor = $command->actor;
$data = $command->data;
$user = $this->users->findOrFail($command->userId, $actor);
$isSelf = $actor->id === $user->id;
$attributes = Arr::get($data, 'attributes', []);
$relationships = Arr::get($data, 'relationships', []);
$validate = [];
if (isset($attributes['username'])) {
$actor->assertCan('editCredentials', $user);
$user->rename($attributes['username']);
}
if (isset($attributes['email'])) {
if ($isSelf) {
$user->requestEmailChange($attributes['email']);
if ($attributes['email'] !== $user->email) {
$validate['email'] = $attributes['email'];
}
} else {
$actor->assertCan('editCredentials', $user);
$user->changeEmail($attributes['email']);
}
}
if (! empty($attributes['isEmailConfirmed'])) {
$actor->assertAdmin();
$user->activate();
}
if (isset($attributes['password'])) {
$actor->assertCan('editCredentials', $user);
$user->changePassword($attributes['password']);
$validate['password'] = $attributes['password'];
}
if (! empty($attributes['markedAllAsReadAt'])) {
$actor->assertPermission($isSelf);
$user->markAllAsRead();
}
if (! empty($attributes['preferences'])) {
$actor->assertPermission($isSelf);
foreach ($attributes['preferences'] as $k => $v) {
$user->setPreference($k, $v);
}
}
if (isset($relationships['groups']['data']) && is_array($relationships['groups']['data'])) {
$actor->assertCan('editGroups', $user);
$oldGroups = $user->groups()->get()->all();
$oldGroupIds = Arr::pluck($oldGroups, 'id');
$newGroupIds = [];
foreach ($relationships['groups']['data'] as $group) {
if ($id = Arr::get($group, 'id')) {
$newGroupIds[] = $id;
}
}
// Ensure non-admins aren't adding/removing admins
$adminChanged = in_array('1', array_diff($oldGroupIds, $newGroupIds)) || in_array('1', array_diff($newGroupIds, $oldGroupIds));
$actor->assertPermission(! $adminChanged || $actor->isAdmin());
$user->raise(
new GroupsChanged($user, $oldGroups)
);
$user->afterSave(function (User $user) use ($newGroupIds) {
$user->groups()->sync($newGroupIds);
$user->unsetRelation('groups');
});
}
$this->events->dispatch(
new Saving($user, $actor, $data)
);
$this->validator->setUser($user);
$this->validator->assertValid(array_merge($user->getDirty(), $validate));
$user->save();
$this->dispatchEventsFor($user, $actor);
return $user;
}
}

View File

@@ -1,21 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\User\Command;
use Flarum\User\User;
class RegisterUser
{
public function __construct(
public User $actor,
public array $data
) {
}
}

View File

@@ -1,154 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\User\Command;
use Flarum\Foundation\DispatchEventsTrait;
use Flarum\Settings\SettingsRepositoryInterface;
use Flarum\User\AvatarUploader;
use Flarum\User\Event\RegisteringFromProvider;
use Flarum\User\Event\Saving;
use Flarum\User\Exception\PermissionDeniedException;
use Flarum\User\RegistrationToken;
use Flarum\User\User;
use Flarum\User\UserValidator;
use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use Illuminate\Validation\Factory;
use Illuminate\Validation\ValidationException;
use Intervention\Image\ImageManager;
use InvalidArgumentException;
class RegisterUserHandler
{
use DispatchEventsTrait;
public function __construct(
protected Dispatcher $events,
protected SettingsRepositoryInterface $settings,
protected UserValidator $userValidator,
protected AvatarUploader $avatarUploader,
private readonly Factory $validator,
protected ImageManager $imageManager
) {
}
/**
* @throws PermissionDeniedException if signup is closed and the actor is
* not an administrator.
* @throws ValidationException
*/
public function handle(RegisterUser $command): User
{
$actor = $command->actor;
$data = $command->data;
if (! $this->settings->get('allow_sign_up')) {
$actor->assertAdmin();
}
$password = Arr::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'])) {
/** @var RegistrationToken $token */
$token = RegistrationToken::validOrFail($data['attributes']['token']);
$password = $password ?: Str::random(20);
}
$user = User::register(
Arr::get($data, 'attributes.username'),
Arr::get($data, 'attributes.email'),
$password
);
if (isset($token)) {
$this->applyToken($user, $token);
}
if ($actor->isAdmin() && Arr::get($data, 'attributes.isEmailConfirmed')) {
$user->activate();
}
$this->events->dispatch(
new Saving($user, $actor, $data)
);
$this->userValidator->assertValid(array_merge($user->getAttributes(), compact('password')));
$user->save();
if (isset($token)) {
$this->fulfillToken($user, $token);
}
$this->dispatchEventsFor($user, $actor);
return $user;
}
private function applyToken(User $user, RegistrationToken $token): void
{
foreach ($token->user_attributes as $k => $v) {
if ($k === 'avatar_url') {
$this->uploadAvatarFromUrl($user, $v);
continue;
}
$user->$k = $v;
if ($k === 'email') {
$user->activate();
}
}
$this->events->dispatch(
new RegisteringFromProvider($user, $token->provider, $token->payload)
);
}
/**
* @throws InvalidArgumentException
*/
private function uploadAvatarFromUrl(User $user, string $url): void
{
$urlValidator = $this->validator->make(compact('url'), [
'url' => 'required|active_url',
]);
if ($urlValidator->fails()) {
throw new InvalidArgumentException('Provided avatar URL must be a valid URI.', 503);
}
$scheme = parse_url($url, PHP_URL_SCHEME);
if (! in_array($scheme, ['http', 'https'])) {
throw new InvalidArgumentException("Provided avatar URL must have scheme http or https. Scheme provided was $scheme.", 503);
}
$image = $this->imageManager->make($url);
$this->avatarUploader->upload($user, $image);
}
private function fulfillToken(User $user, RegistrationToken $token): void
{
$token->delete();
if ($token->provider && $token->identifier) {
$user->loginProviders()->create([
'provider' => $token->provider,
'identifier' => $token->identifier
]);
}
}
}