From 649aeb362790f592c6d68244a985809b3026d8ef Mon Sep 17 00:00:00 2001 From: myrmidex Date: Sun, 26 Apr 2026 20:18:18 +0200 Subject: [PATCH] chore - Extract RegisterDiscoveredPageAction for shared Page::firstOrCreate logic --- app/Actions/RegisterDiscoveredPageAction.php | 22 +++++ app/Listeners/UrlDiscoveredListener.php | 17 ++-- app/Livewire/UrlSubmissionForm.php | 10 +-- .../RegisterDiscoveredPageActionTest.php | 83 +++++++++++++++++++ 4 files changed, 115 insertions(+), 17 deletions(-) create mode 100644 app/Actions/RegisterDiscoveredPageAction.php create mode 100644 tests/Unit/Actions/RegisterDiscoveredPageActionTest.php diff --git a/app/Actions/RegisterDiscoveredPageAction.php b/app/Actions/RegisterDiscoveredPageAction.php new file mode 100644 index 0000000..840e52c --- /dev/null +++ b/app/Actions/RegisterDiscoveredPageAction.php @@ -0,0 +1,22 @@ + $url], + [ + 'status' => PageStatusEnum::Discovered, + 'instance_id' => $instanceId, + ], + ); + } +} diff --git a/app/Listeners/UrlDiscoveredListener.php b/app/Listeners/UrlDiscoveredListener.php index 535951a..67b4f1f 100644 --- a/app/Listeners/UrlDiscoveredListener.php +++ b/app/Listeners/UrlDiscoveredListener.php @@ -4,8 +4,7 @@ namespace App\Listeners; -use App\Enums\PageStatusEnum; -use App\Models\Page; +use App\Actions\RegisterDiscoveredPageAction; use App\Models\PageLink; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Support\Facades\DB; @@ -13,22 +12,20 @@ class UrlDiscoveredListener implements ShouldQueue { + public function __construct( + private RegisterDiscoveredPageAction $registerPage, + ) {} + public function handle(UrlDiscovered $event): void { DB::transaction(function () use ($event) { - $targetPage = Page::firstOrCreate( - ['url' => $event->url], - ['status' => PageStatusEnum::Discovered, 'instance_id' => $event->instanceId], - ); + $targetPage = ($this->registerPage)($event->url, $event->instanceId); if ($event->postUrl === null || $event->postUrl === $event->url) { return; } - $sourcePage = Page::firstOrCreate( - ['url' => $event->postUrl], - ['status' => PageStatusEnum::Discovered, 'instance_id' => $event->instanceId], - ); + $sourcePage = ($this->registerPage)($event->postUrl, $event->instanceId); PageLink::firstOrCreate([ 'source_page_id' => $sourcePage->id, diff --git a/app/Livewire/UrlSubmissionForm.php b/app/Livewire/UrlSubmissionForm.php index bbf2000..8c1b11e 100644 --- a/app/Livewire/UrlSubmissionForm.php +++ b/app/Livewire/UrlSubmissionForm.php @@ -4,8 +4,7 @@ namespace App\Livewire; -use App\Enums\PageStatusEnum; -use App\Models\Page; +use App\Actions\RegisterDiscoveredPageAction; use Illuminate\Contracts\View\View; use Illuminate\Support\Facades\RateLimiter; use Livewire\Component; @@ -16,7 +15,7 @@ class UrlSubmissionForm extends Component public ?string $confirmedUrl = null; - public function submit(): void + public function submit(RegisterDiscoveredPageAction $registerPage): void { $key = 'submit-url:' . request()->ip(); @@ -32,10 +31,7 @@ public function submit(): void 'url' => ['required', 'url:http,https'], ]); - Page::firstOrCreate( - ['url' => $validated['url']], - ['status' => PageStatusEnum::Discovered], - ); + $registerPage($validated['url']); $this->confirmedUrl = $validated['url']; $this->reset('url'); diff --git a/tests/Unit/Actions/RegisterDiscoveredPageActionTest.php b/tests/Unit/Actions/RegisterDiscoveredPageActionTest.php new file mode 100644 index 0000000..f993940 --- /dev/null +++ b/tests/Unit/Actions/RegisterDiscoveredPageActionTest.php @@ -0,0 +1,83 @@ +assertInstanceOf(Page::class, $page); + $this->assertSame('https://example.com/article', $page->url); + $this->assertSame(PageStatusEnum::Discovered, $page->status); + $this->assertNull($page->instance_id); + $this->assertDatabaseHas('pages', ['url' => 'https://example.com/article']); + } + + public function test_creates_page_with_provided_instance_id(): void + { + $instance = Instance::factory() + ->type(InstanceType::Mastodon) + ->enabled() + ->create(); + + $action = new RegisterDiscoveredPageAction; + + $page = $action('https://example.com/fediverse-post', instanceId: $instance->id); + + $this->assertInstanceOf(Page::class, $page); + $this->assertSame($instance->id, $page->instance_id); + $this->assertDatabaseHas('pages', [ + 'url' => 'https://example.com/fediverse-post', + 'instance_id' => $instance->id, + ]); + } + + public function test_returns_existing_page_when_url_already_exists(): void + { + $existing = Page::factory()->createQuietly([ + 'url' => 'https://example.com/seen-before', + 'status' => PageStatusEnum::Discovered, + ]); + + $action = new RegisterDiscoveredPageAction; + + $returned = $action('https://example.com/seen-before'); + + $this->assertSame($existing->id, $returned->id); + $this->assertDatabaseCount('pages', 1); + } + + public function test_existing_page_status_not_overwritten_on_duplicate_call(): void + { + Page::factory()->createQuietly([ + 'url' => 'https://example.com/already-fetched', + 'status' => PageStatusEnum::Fetched, + ]); + + $action = new RegisterDiscoveredPageAction; + + $returned = $action('https://example.com/already-fetched'); + + $this->assertSame(PageStatusEnum::Fetched, $returned->status); + $this->assertDatabaseHas('pages', [ + 'url' => 'https://example.com/already-fetched', + 'status' => PageStatusEnum::Fetched, + ]); + } +}