1
0
mirror of https://github.com/flarum/core.git synced 2025-07-28 20:20:34 +02:00

Merge pull request from GHSA-hph3-hv3c-7725

* test: add reply creation tests

Signed-off-by: Sami Mazouz <sychocouldy@gmail.com>

* fix: access checking being bypassed for post creation when first post is deleted

Signed-off-by: Sami Mazouz <sychocouldy@gmail.com>

* chore: recover tests

Signed-off-by: Sami Mazouz <sychocouldy@gmail.com>

* chore: make provider public

Signed-off-by: Sami Mazouz <sychocouldy@gmail.com>

Signed-off-by: Sami Mazouz <sychocouldy@gmail.com>
This commit is contained in:
Sami Mazouz
2023-01-10 12:45:29 +01:00
parent 248a71d9b5
commit 12dfcc5c79
4 changed files with 50 additions and 9 deletions

View File

@@ -79,7 +79,7 @@ class StartDiscussionHandler
// We will do this by running the PostReply command. // We will do this by running the PostReply command.
try { try {
$post = $this->bus->dispatch( $post = $this->bus->dispatch(
new PostReply($discussion->id, $actor, $data, $ipAddress) new PostReply($discussion->id, $actor, $data, $ipAddress, true)
); );
} catch (Exception $e) { } catch (Exception $e) {
$discussion->delete(); $discussion->delete();

View File

@@ -41,17 +41,23 @@ class PostReply
*/ */
public $ipAddress; public $ipAddress;
/**
* @var bool
*/
public $isFirstPost;
/** /**
* @param int $discussionId The ID of the discussion to post the reply to. * @param int $discussionId The ID of the discussion to post the reply to.
* @param User $actor The user who is performing the action. * @param User $actor The user who is performing the action.
* @param array $data The attributes to assign to the new post. * @param array $data The attributes to assign to the new post.
* @param string $ipAddress The IP address of the actor. * @param string $ipAddress The IP address of the actor.
*/ */
public function __construct($discussionId, User $actor, array $data, $ipAddress = null) public function __construct($discussionId, User $actor, array $data, $ipAddress = null, bool $isFirstPost = false)
{ {
$this->discussionId = $discussionId; $this->discussionId = $discussionId;
$this->actor = $actor; $this->actor = $actor;
$this->data = $data; $this->data = $data;
$this->ipAddress = $ipAddress; $this->ipAddress = $ipAddress;
$this->isFirstPost = $isFirstPost;
} }
} }

View File

@@ -74,7 +74,7 @@ class PostReplyHandler
// If this is the first post in the discussion, it's technically not a // If this is the first post in the discussion, it's technically not a
// "reply", so we won't check for that permission. // "reply", so we won't check for that permission.
if ($discussion->first_post_id !== null) { if (! $command->isFirstPost) {
$actor->assertCan('reply', $discussion); $actor->assertCan('reply', $discussion);
} }

View File

@@ -10,6 +10,7 @@
namespace Flarum\Tests\integration\api\posts; namespace Flarum\Tests\integration\api\posts;
use Carbon\Carbon; use Carbon\Carbon;
use Flarum\Group\Group;
use Flarum\Testing\integration\RetrievesAuthorizedUsers; use Flarum\Testing\integration\RetrievesAuthorizedUsers;
use Flarum\Testing\integration\TestCase; use Flarum\Testing\integration\TestCase;
@@ -26,36 +27,70 @@ class CreateTest extends TestCase
$this->prepareDatabase([ $this->prepareDatabase([
'discussions' => [ 'discussions' => [
['id' => 1, 'title' => __CLASS__, 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 2], ['id' => 1, 'title' => __CLASS__, 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 2, 'first_post_id' => 1],
// Discussion with deleted first post.
['id' => 2, 'title' => __CLASS__, 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 2, 'first_post_id' => null],
],
'posts' => [
['id' => 1, 'discussion_id' => 1, 'number' => 1, 'created_at' => Carbon::now()->subDay()->toDateTimeString(), 'user_id' => 2, 'type' => 'comment', 'content' => '<t></t>'],
], ],
'users' => [ 'users' => [
$this->normalUser(), $this->normalUser(),
] ['id' => 3, 'username' => 'restricted', 'email' => 'restricted@machine.local', 'is_email_confirmed' => 1],
],
'groups' => [
['id' => 40, 'name_singular' => 'tess', 'name_plural' => 'tess'],
],
'group_user' => [
['group_id' => 40, 'user_id' => 3],
],
'group_permission' => [
['group_id' => 40, 'permission' => 'discussion.reply'],
],
]); ]);
} }
/** /**
* @dataProvider discussionRepliesPrvider
* @test * @test
*/ */
public function can_create_reply() public function can_create_reply_if_allowed(int $actorId, int $discussionId, int $responseStatus)
{ {
// Reset permissions for normal users group.
$this->database()
->table('group_permission')
->where('permission', 'discussion.reply')
->where('group_id', Group::MEMBER_ID)
->delete();
$response = $this->send( $response = $this->send(
$this->request('POST', '/api/posts', [ $this->request('POST', '/api/posts', [
'authenticatedAs' => 2, 'authenticatedAs' => $actorId,
'json' => [ 'json' => [
'data' => [ 'data' => [
'attributes' => [ 'attributes' => [
'content' => 'reply with predetermined content for automated testing - too-obscure', 'content' => 'reply with predetermined content for automated testing - too-obscure',
], ],
'relationships' => [ 'relationships' => [
'discussion' => ['data' => ['id' => 1]], 'discussion' => ['data' => ['id' => $discussionId]],
], ],
], ],
], ],
]) ])
); );
$this->assertEquals(201, $response->getStatusCode()); $this->assertEquals($responseStatus, $response->getStatusCode());
}
public function discussionRepliesPrvider(): array
{
return [
// [$actorId, $discussionId, $responseStatus]
'can_create_reply_with_ability' => [3, 1, 201],
'cannot_create_reply_without_ability' => [2, 1, 403],
'can_create_reply_with_ability_when_first_post_is_deleted' => [3, 2, 201],
'cannot_create_reply_without_ability_when_first_post_is_deleted' => [2, 2, 403],
];
} }
/** /**