Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@
"FoF\\Split\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"FoF\\Split\\Tests\\": "tests/"
}
},
"require-dev": {
"flarum/phpstan": "^2.0.0",
"flarum/testing": "^2.0.0",
Expand All @@ -61,10 +66,14 @@
},
"scripts": {
"analyse:phpstan": "phpstan analyse",
"clear-cache:phpstan": "phpstan clear-result-cache"
"clear-cache:phpstan": "phpstan clear-result-cache",
"test:integration": "phpunit -c tests/phpunit.integration.xml",
"test:setup": "@php tests/integration/setup.php"
},
"scripts-descriptions": {
"analyse:phpstan": "Run static analysis"
"analyse:phpstan": "Run static analysis",
"test:integration": "Runs integration tests.",
"test:setup": "Sets up a database for use with integration tests. Execute this only once."
},
"minimum-stability": "beta",
"prefer-stable": true
Expand Down
12 changes: 10 additions & 2 deletions src/Api/Commands/SplitDiscussionHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,18 @@ public function handle(SplitDiscussion $command)
/** @var Discussion $originalDiscussion */
$originalDiscussion = $startPost->discussion;

// create a new discussion for the user of the first splitted reply.
$discussion = Discussion::start($command->title, $startPost->user);
// Imported or edited posts can have no author; fall back to the acting user
// so the new discussion still goes through the supported core start path.
$discussionAuthor = $startPost->user ?? $command->actor;

$discussion = Discussion::start($command->title, $discussionAuthor);
$discussion->setFirstPost($startPost);

if ($startPost->user_id === null) {
$discussion->user_id = $discussionAuthor->id;
$discussion->setRelation('user', $discussionAuthor);
}

// persist the new discussion.
$discussion->save();

Expand Down
210 changes: 210 additions & 0 deletions tests/integration/api/SplitDiscussionTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
<?php

/*
* This file is part of fof/split.
*
* Copyright (c) Flagrow.
* Copyright (c) 2020 FriendsOfFlarum
*
* For the full copyright and license information, please view the LICENSE.md
* file that was distributed with this source code.
*/

namespace FoF\Split\Tests\integration\api;

use Flarum\Testing\integration\TestCase;
use PHPUnit\Framework\Attributes\Test;

class SplitDiscussionTest extends TestCase
{
protected function setUp(): void
{
parent::setUp();

$this->extension('fof-split');

$this->prepareDatabase([
'discussions' => [
[
'id' => 1,
'title' => 'Original Discussion',
'slug' => 'original-discussion',
'comment_count' => 5,
'participant_count' => 1,
'created_at' => '2024-01-01 00:00:00',
'user_id' => 1,
'first_post_id' => 1,
'last_posted_at' => '2024-01-01 00:04:00',
'last_posted_user_id' => 1,
'last_post_id' => 5,
'last_post_number' => 5,
],
],
'posts' => [
[
'id' => 1,
'discussion_id' => 1,
'number' => 1,
'created_at' => '2024-01-01 00:00:00',
'user_id' => 1,
'type' => 'comment',
'content' => '<p>Opening post</p>',
'ip_address' => '127.0.0.1',
'is_private' => 0,
],
[
'id' => 2,
'discussion_id' => 1,
'number' => 2,
'created_at' => '2024-01-01 00:01:00',
'user_id' => null,
'type' => 'comment',
'content' => '<p>Deleted author reply</p>',
'ip_address' => '127.0.0.1',
'is_private' => 0,
],
[
'id' => 3,
'discussion_id' => 1,
'number' => 3,
'created_at' => '2024-01-01 00:02:00',
'user_id' => null,
'type' => 'comment',
'content' => '<p>Deleted author follow-up</p>',
'ip_address' => '127.0.0.1',
'is_private' => 0,
],
[
'id' => 4,
'discussion_id' => 1,
'number' => 4,
'created_at' => '2024-01-01 00:03:00',
'user_id' => 1,
'type' => 'comment',
'content' => '<p>Existing author reply</p>',
'ip_address' => '127.0.0.1',
'is_private' => 0,
],
[
'id' => 5,
'discussion_id' => 1,
'number' => 5,
'created_at' => '2024-01-01 00:04:00',
'user_id' => 1,
'type' => 'comment',
'content' => '<p>Existing author follow-up</p>',
'ip_address' => '127.0.0.1',
'is_private' => 0,
],
],
]);
}

#[Test]
public function it_can_split_posts_when_the_selected_start_post_author_has_been_deleted(): void
{
$response = $this->sendSplitRequest('Split Discussion', 2, 3);

$this->assertSame(200, $response->getStatusCode());

$payload = json_decode((string) $response->getBody(), true);

$this->assertIsArray($payload);
$this->assertSame('Split Discussion', $payload['data']['attributes']['title']);

$newDiscussionId = (int) $payload['data']['id'];

$discussion = $this->database()->table('discussions')->where('id', $newDiscussionId)->first();

$this->assertNotNull($discussion);
$this->assertSame(2, $discussion->first_post_id);
$this->assertSame(1, $discussion->user_id);

$splitPosts = $this->database()->table('posts')
->where('discussion_id', $newDiscussionId)
->where('type', 'comment')
->orderBy('number')
->pluck('id')
->all();

$this->assertSame([2, 3], $splitPosts);
}

#[Test]
public function it_still_uses_the_normal_creation_path_when_the_start_post_author_exists(): void
{
$response = $this->sendSplitRequest('Normal Split Discussion', 4, 5);

$this->assertSame(200, $response->getStatusCode());

$payload = json_decode((string) $response->getBody(), true);

$this->assertIsArray($payload);

$newDiscussionId = (int) $payload['data']['id'];

$discussion = $this->database()->table('discussions')->where('id', $newDiscussionId)->first();

$this->assertNotNull($discussion);
$this->assertSame(4, $discussion->first_post_id);
$this->assertSame(1, $discussion->user_id);

$renumberedPosts = $this->database()->table('posts')
->where('discussion_id', $newDiscussionId)
->where('type', 'comment')
->orderBy('id')
->pluck('number')
->all();

$this->assertSame([1, 2], $renumberedPosts);
}

#[Test]
public function it_refreshes_original_discussion_metadata_and_creates_split_event_posts(): void
{
$response = $this->sendSplitRequest('Split Discussion', 2, 3);

$this->assertSame(200, $response->getStatusCode());

$payload = json_decode((string) $response->getBody(), true);

$this->assertIsArray($payload);

$newDiscussionId = (int) $payload['data']['id'];

$originalDiscussion = $this->database()->table('discussions')->where('id', 1)->first();

$this->assertNotNull($originalDiscussion);
$this->assertSame(3, $originalDiscussion->comment_count);
$this->assertSame(1, $originalDiscussion->participant_count);
$this->assertSame(5, $originalDiscussion->last_post_id);
$this->assertSame(5, $originalDiscussion->last_post_number);

$originalSplitPosts = $this->database()->table('posts')
->where('discussion_id', 1)
->where('type', 'discussionSplit')
->count();

$newSplitPosts = $this->database()->table('posts')
->where('discussion_id', $newDiscussionId)
->where('type', 'discussionSplit')
->count();

$this->assertSame(1, $originalSplitPosts);
$this->assertSame(1, $newSplitPosts);
}

protected function sendSplitRequest(string $title, int $startPostId, int $endPostNumber)
{
$request = $this->request('POST', '/api/split', [
'authenticatedAs' => 1,
'json' => [
'title' => $title,
'start_post_id' => $startPostId,
'end_post_number' => $endPostNumber,
],
]);

return $this->send($request);
}
}
19 changes: 19 additions & 0 deletions tests/integration/setup.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

/*
* This file is part of fof/split.
*
* Copyright (c) Flagrow.
* Copyright (c) 2020 FriendsOfFlarum
*
* For the full copyright and license information, please view the LICENSE.md
* file that was distributed with this source code.
*/

use Flarum\Testing\integration\Setup\SetupScript;

require __DIR__.'/../../vendor/autoload.php';

$setup = new SetupScript();

$setup->run();
21 changes: 21 additions & 0 deletions tests/phpunit.integration.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/11.5/phpunit.xsd"
backupGlobals="false"
bootstrap="integration/setup.php"
colors="true"
processIsolation="true"
stopOnFailure="false"
>
<source>
<include>
<directory suffix=".php">../src/</directory>
</include>
</source>
<testsuites>
<testsuite name="Flarum Integration Tests">
<directory suffix="Test.php">./integration</directory>
</testsuite>
</testsuites>
</phpunit>
Loading