diff --git a/framework/core/src/Post/CommentPost.php b/framework/core/src/Post/CommentPost.php index c1b150ddb3..b5d9066aab 100644 --- a/framework/core/src/Post/CommentPost.php +++ b/framework/core/src/Post/CommentPost.php @@ -28,6 +28,8 @@ class CommentPost extends Post public static string $type = 'comment'; protected static Formatter $formatter; + protected $observables = ['hidden']; + public static function reply(int $discussionId, string $content, int $userId, ?string $ipAddress, ?User $actor = null): static { $post = new static; @@ -69,6 +71,12 @@ public function hide(?User $actor = null): static $this->hidden_user_id = $actor?->id; $this->raise(new Hidden($this)); + + $this->saved(function (self $model) { + if ($model === $this) { + $model->fireModelEvent('hidden', false); + } + }); } return $this; @@ -81,6 +89,12 @@ public function restore(): static $this->hidden_user_id = null; $this->raise(new Restored($this)); + + $this->saved(function (self $model) { + if ($model === $this) { + $model->fireModelEvent('restored', false); + } + }); } return $this; diff --git a/framework/core/tests/integration/extenders/SimpleFlarumSearchTest.php b/framework/core/tests/integration/extenders/SearchDriverTest.php similarity index 97% rename from framework/core/tests/integration/extenders/SimpleFlarumSearchTest.php rename to framework/core/tests/integration/extenders/SearchDriverTest.php index 28c706ac87..8c8d8ea3b3 100644 --- a/framework/core/tests/integration/extenders/SimpleFlarumSearchTest.php +++ b/framework/core/tests/integration/extenders/SearchDriverTest.php @@ -24,7 +24,7 @@ use Flarum\Testing\integration\TestCase; use Flarum\User\User; -class SimpleFlarumSearchTest extends TestCase +class SearchDriverTest extends TestCase { use RetrievesAuthorizedUsers; @@ -73,8 +73,7 @@ public function searchDiscussions($query, $limit = null, array $filters = []) return $this->app() ->getContainer() ->make(SearchManager::class) - ->for(Discussion::class) - ->search(new SearchCriteria($actor, $filters, $limit)) + ->query(Discussion::class, new SearchCriteria($actor, $filters, $limit)) ->getResults(); } diff --git a/framework/core/tests/integration/extenders/SearchIndexTest.php b/framework/core/tests/integration/extenders/SearchIndexTest.php new file mode 100644 index 0000000000..acbb3ead43 --- /dev/null +++ b/framework/core/tests/integration/extenders/SearchIndexTest.php @@ -0,0 +1,222 @@ +prepareDatabase([ + 'discussions' => [ + ['id' => 1, 'title' => 'DISCUSSION 1', 'created_at' => Carbon::now()->subDays(1)->toDateTimeString(), 'hidden_at' => null, 'comment_count' => 1, 'user_id' => 1, 'first_post_id' => 1], + ['id' => 2, 'title' => 'DISCUSSION 2', 'created_at' => Carbon::now()->subDays(2)->toDateTimeString(), 'hidden_at' => Carbon::now(), 'comment_count' => 1, 'user_id' => 1], + ], + 'posts' => [ + ['id' => 1, 'number' => 1, 'discussion_id' => 1, 'created_at' => Carbon::now(), 'user_id' => 1, 'type' => 'comment', 'content' => '

content

', 'hidden_at' => null], + ['id' => 2, 'number' => 2, 'discussion_id' => 1, 'created_at' => Carbon::now(), 'user_id' => 1, 'type' => 'comment', 'content' => '

content

', 'hidden_at' => Carbon::now()], + ], + ]); + } + + public static function modelProvider(): array + { + return [ + ['discussions', Discussion::class, 'title'], + ['posts', CommentPost::class, 'content'], + ]; + } + + /** @dataProvider modelProvider */ + public function test_indexer_triggered_on_create(string $type, string $modelClass, string $attribute) + { + $this->extend( + (new Extend\SearchIndex()) + ->indexer($modelClass, TestIndexer::class) + ); + + // Create discussion + $response = $this->send( + $this->request('POST', "/api/$type", [ + 'authenticatedAs' => 1, + 'json' => [ + 'data' => [ + 'attributes' => [ + $attribute => 'test', + ], + 'relationships' => + ($type === 'posts' ? [ + 'discussion' => [ + 'data' => [ + 'type' => 'discussions', + 'id' => 1, + ], + ], + ] : null), + ] + ], + ]), + ); + + Assert::assertEquals('save', TestIndexer::$triggered, $response->getBody()->getContents()); + } + + /** @dataProvider modelProvider */ + public function test_indexer_triggered_on_save(string $type, string $modelClass, string $attribute) + { + $this->extend( + (new Extend\SearchIndex()) + ->indexer($modelClass, TestIndexer::class) + ); + + // Rename discussion + $response = $this->send( + $this->request('PATCH', "/api/$type/1", [ + 'authenticatedAs' => 1, + 'json' => [ + 'data' => [ + 'attributes' => [ + $attribute => 'changed' + ] + ] + ], + ]), + ); + + Assert::assertEquals('save', TestIndexer::$triggered, $response->getBody()->getContents()); + } + + /** @dataProvider modelProvider */ + public function test_indexer_triggered_on_delete(string $type, string $modelClass, string $attribute) + { + $this->extend( + (new Extend\SearchIndex()) + ->indexer($modelClass, TestIndexer::class) + ); + + // Delete discussion + $response = $this->send( + $this->request('DELETE', "/api/$type/1", [ + 'authenticatedAs' => 1, + 'json' => [], + ]), + ); + + Assert::assertEquals('delete', TestIndexer::$triggered, $response->getBody()->getContents()); + } + + /** @dataProvider modelProvider */ + public function test_indexer_triggered_on_hide(string $type, string $modelClass, string $attribute) + { + $this->extend( + (new Extend\SearchIndex()) + ->indexer($modelClass, TestIndexer::class) + ); + + // Hide discussion + $response = $this->send( + $this->request('PATCH', "/api/$type/1", [ + 'authenticatedAs' => 1, + 'json' => [ + 'data' => [ + 'attributes' => [ + 'isHidden' => true + ] + ] + ], + ]), + ); + + Assert::assertEquals('delete', TestIndexer::$triggered, $response->getBody()->getContents()); + } + + /** @dataProvider modelProvider */ + public function test_indexer_triggered_on_restore(string $type, string $modelClass, string $attribute) + { + $this->extend( + (new Extend\SearchIndex()) + ->indexer($modelClass, TestIndexer::class) + ); + + // Restore discussion + $response = $this->send( + $this->request('PATCH', "/api/$type/2", [ + 'authenticatedAs' => 1, + 'json' => [ + 'data' => [ + 'attributes' => [ + 'isHidden' => false + ] + ] + ], + ]), + ); + + Assert::assertEquals('save', TestIndexer::$triggered, $response->getBody()->getContents()); + } + + protected function tearDown(): void + { + TestIndexer::$triggered = null; + + parent::tearDown(); + } +} + +class TestIndexer implements IndexerInterface +{ + public static ?string $triggered = null; + + public static function index(): string + { + return 'test'; + } + + public function save(array $models): void + { + self::$triggered = 'save'; + } + + public function delete(array $models): void + { + self::$triggered = 'delete'; + } + + public function build(): void + { + // + } + + public function flush(): void + { + // + } +}