diff --git a/.github/workflows/backend.yml b/.github/workflows/backend.yml index 793bebb..ea60fea 100644 --- a/.github/workflows/backend.yml +++ b/.github/workflows/backend.yml @@ -6,7 +6,7 @@ jobs: run: uses: flarum/framework/.github/workflows/REUSABLE_backend.yml@2.x with: - enable_backend_testing: false + enable_backend_testing: true enable_phpstan: true backend_directory: . diff --git a/composer.json b/composer.json index 686e3fb..8388fc7 100644 --- a/composer.json +++ b/composer.json @@ -54,17 +54,35 @@ } }, "require-dev": { + "flarum/audit": "2.x-dev", "flarum/phpstan": "^2.0.0", "flarum/testing": "^2.0.0", "flarum/tags": "*", - "flarum/flags": "*" + "flarum/flags": "*", + "flarum/realtime": "*" }, "scripts": { "analyse:phpstan": "phpstan analyse", - "clear-cache:phpstan": "phpstan clear-result-cache" + "clear-cache:phpstan": "phpstan clear-result-cache", + "test": [ + "@test:unit", + "@test:integration" + ], + "test:unit": "phpunit -c tests/phpunit.unit.xml", + "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": "Runs all tests.", + "test:unit": "Runs all unit tests.", + "test:integration": "Runs all integration tests.", + "test:setup": "Sets up a database for use with integration tests. Execute this only once." + }, + "autoload-dev": { + "psr-4": { + "FoF\\Split\\Tests\\": "tests/" + } }, "minimum-stability": "beta", "prefer-stable": true diff --git a/extend.php b/extend.php index f32da34..eff943f 100644 --- a/extend.php +++ b/extend.php @@ -15,6 +15,8 @@ use Flarum\Api\Context; use Flarum\Api\Resource; use Flarum\Api\Schema; +use Flarum\Audit\AuditLogger; +use Flarum\Audit\Extend\Audit; use Flarum\Discussion\Discussion; use Flarum\Discussion\Event\Renamed; use Flarum\Extend; @@ -46,4 +48,25 @@ Schema\Boolean::make('canSplit') ->get(fn (Discussion $discussion, Context $context) => $context->getActor()->can('split', $discussion)), ]), + + (new Extend\Conditional()) + ->whenExtensionEnabled('flarum-audit', fn () => [ + (new Audit()) + ->group('fof-split') + ->register('discussion.split_away', 'discussion.split_into') + ->using(function () { + resolve('events')->listen(DiscussionWasSplit::class, function (DiscussionWasSplit $event) { + AuditLogger::log('discussion.split_away', [ + 'discussion_id' => $event->originalDiscussion->id, + 'new_discussion_id' => $event->newDiscussion->id, + 'post_count' => $event->posts->count(), + ]); + AuditLogger::log('discussion.split_into', [ + 'discussion_id' => $event->newDiscussion->id, + 'original_discussion_id' => $event->originalDiscussion->id, + 'post_count' => $event->posts->count(), + ]); + }); + }), + ]), ]; diff --git a/locale/en.yml b/locale/en.yml index b19bb6c..1731917 100644 --- a/locale/en.yml +++ b/locale/en.yml @@ -14,3 +14,13 @@ fof-split: title: Split discussion new_discussion_label: Specify the title for the new discussion submit_button: Split + +# Labels for the audit log entries this extension produces, rendered by the (optional) +# flarum/audit browser. Defined under the flarum-audit namespace so the audit frontend +# resolves them, but shipped here so they travel with the extension that owns the actions. +flarum-audit: + lib: + browser: + discussion: + split_away: Split {post_count} posts from {discussion} into {new_discussion} + split_into: Split {post_count} posts into new discussion {discussion} diff --git a/tests/fixtures/.gitkeep b/tests/fixtures/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/tests/integration/AuditTest.php b/tests/integration/AuditTest.php new file mode 100644 index 0000000..bfb6dd9 --- /dev/null +++ b/tests/integration/AuditTest.php @@ -0,0 +1,92 @@ +extension('flarum-audit', 'fof-split'); + + $date = Carbon::parse('2021-01-01T12:00:00+00:00'); + + $this->prepareDatabase([ + 'audit_log' => [], + Discussion::class => [ + ['id' => 10, 'title' => 'A', 'created_at' => $date, 'last_posted_at' => $date, 'first_post_id' => 1, 'comment_count' => 4], + ], + Post::class => [ + ['id' => 1, 'number' => 1, 'discussion_id' => 10, 'created_at' => $date, 'type' => 'comment', 'content' => '

A

'], + ['id' => 2, 'number' => 2, 'discussion_id' => 10, 'created_at' => $date, 'type' => 'comment', 'content' => '

B

', 'user_id' => 1], + ['id' => 3, 'number' => 3, 'discussion_id' => 10, 'created_at' => $date, 'type' => 'comment', 'content' => '

C

'], + ['id' => 4, 'number' => 4, 'discussion_id' => 10, 'created_at' => $date, 'type' => 'comment', 'content' => '

D

'], + ], + ]); + } + + #[Test] + public function split() + { + $response = $this->send($this->request('POST', '/api/split', [ + 'authenticatedAs' => 1, + 'json' => [ + 'title' => 'Split', + 'start_post_id' => 2, + 'end_post_number' => 3, + ], + ])); + + $body = $response->getBody()->getContents(); + + $this->assertEquals(200, $response->getStatusCode(), $body); + + $newDiscussionId = Arr::get(json_decode($body, true), 'data.id'); + + $log = AuditLog::query()->where('action', 'discussion.split_away')->first(); + $this->assertNotNull($log); + $this->assertEquals(1, $log->actor_id); + $this->assertEquals([ + 'discussion_id' => 10, + 'new_discussion_id' => $newDiscussionId, + 'post_count' => 2, + ], $log->payload); + $this->assertEquals('127.0.0.1', $log->ip_address); + + $log = AuditLog::query()->where('action', 'discussion.split_into')->first(); + $this->assertNotNull($log); + $this->assertEquals(1, $log->actor_id); + $this->assertEquals([ + 'discussion_id' => $newDiscussionId, + 'original_discussion_id' => 10, + 'post_count' => 2, + ], $log->payload); + $this->assertEquals('127.0.0.1', $log->ip_address); + } +} diff --git a/tests/integration/setup.php b/tests/integration/setup.php new file mode 100644 index 0000000..3281430 --- /dev/null +++ b/tests/integration/setup.php @@ -0,0 +1,19 @@ +run(); diff --git a/tests/phpunit.integration.xml b/tests/phpunit.integration.xml new file mode 100644 index 0000000..90fbbff --- /dev/null +++ b/tests/phpunit.integration.xml @@ -0,0 +1,25 @@ + + + + + ../src/ + + + + + ./integration + ./integration/tmp + + + diff --git a/tests/phpunit.unit.xml b/tests/phpunit.unit.xml new file mode 100644 index 0000000..d3a4a3e --- /dev/null +++ b/tests/phpunit.unit.xml @@ -0,0 +1,27 @@ + + + + + ../src/ + + + + + ./unit + + + + + + diff --git a/tests/unit/.gitkeep b/tests/unit/.gitkeep new file mode 100644 index 0000000..e69de29