chore - Extract RegisterDiscoveredPageAction for shared Page::firstOrCreate logic
This commit is contained in:
parent
dda5b0f770
commit
649aeb3627
4 changed files with 115 additions and 17 deletions
22
app/Actions/RegisterDiscoveredPageAction.php
Normal file
22
app/Actions/RegisterDiscoveredPageAction.php
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Actions;
|
||||||
|
|
||||||
|
use App\Enums\PageStatusEnum;
|
||||||
|
use App\Models\Page;
|
||||||
|
|
||||||
|
class RegisterDiscoveredPageAction
|
||||||
|
{
|
||||||
|
public function __invoke(string $url, ?int $instanceId = null): Page
|
||||||
|
{
|
||||||
|
return Page::firstOrCreate(
|
||||||
|
['url' => $url],
|
||||||
|
[
|
||||||
|
'status' => PageStatusEnum::Discovered,
|
||||||
|
'instance_id' => $instanceId,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,8 +4,7 @@
|
||||||
|
|
||||||
namespace App\Listeners;
|
namespace App\Listeners;
|
||||||
|
|
||||||
use App\Enums\PageStatusEnum;
|
use App\Actions\RegisterDiscoveredPageAction;
|
||||||
use App\Models\Page;
|
|
||||||
use App\Models\PageLink;
|
use App\Models\PageLink;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
@ -13,22 +12,20 @@
|
||||||
|
|
||||||
class UrlDiscoveredListener implements ShouldQueue
|
class UrlDiscoveredListener implements ShouldQueue
|
||||||
{
|
{
|
||||||
|
public function __construct(
|
||||||
|
private RegisterDiscoveredPageAction $registerPage,
|
||||||
|
) {}
|
||||||
|
|
||||||
public function handle(UrlDiscovered $event): void
|
public function handle(UrlDiscovered $event): void
|
||||||
{
|
{
|
||||||
DB::transaction(function () use ($event) {
|
DB::transaction(function () use ($event) {
|
||||||
$targetPage = Page::firstOrCreate(
|
$targetPage = ($this->registerPage)($event->url, $event->instanceId);
|
||||||
['url' => $event->url],
|
|
||||||
['status' => PageStatusEnum::Discovered, 'instance_id' => $event->instanceId],
|
|
||||||
);
|
|
||||||
|
|
||||||
if ($event->postUrl === null || $event->postUrl === $event->url) {
|
if ($event->postUrl === null || $event->postUrl === $event->url) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$sourcePage = Page::firstOrCreate(
|
$sourcePage = ($this->registerPage)($event->postUrl, $event->instanceId);
|
||||||
['url' => $event->postUrl],
|
|
||||||
['status' => PageStatusEnum::Discovered, 'instance_id' => $event->instanceId],
|
|
||||||
);
|
|
||||||
|
|
||||||
PageLink::firstOrCreate([
|
PageLink::firstOrCreate([
|
||||||
'source_page_id' => $sourcePage->id,
|
'source_page_id' => $sourcePage->id,
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,7 @@
|
||||||
|
|
||||||
namespace App\Livewire;
|
namespace App\Livewire;
|
||||||
|
|
||||||
use App\Enums\PageStatusEnum;
|
use App\Actions\RegisterDiscoveredPageAction;
|
||||||
use App\Models\Page;
|
|
||||||
use Illuminate\Contracts\View\View;
|
use Illuminate\Contracts\View\View;
|
||||||
use Illuminate\Support\Facades\RateLimiter;
|
use Illuminate\Support\Facades\RateLimiter;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
@ -16,7 +15,7 @@ class UrlSubmissionForm extends Component
|
||||||
|
|
||||||
public ?string $confirmedUrl = null;
|
public ?string $confirmedUrl = null;
|
||||||
|
|
||||||
public function submit(): void
|
public function submit(RegisterDiscoveredPageAction $registerPage): void
|
||||||
{
|
{
|
||||||
$key = 'submit-url:' . request()->ip();
|
$key = 'submit-url:' . request()->ip();
|
||||||
|
|
||||||
|
|
@ -32,10 +31,7 @@ public function submit(): void
|
||||||
'url' => ['required', 'url:http,https'],
|
'url' => ['required', 'url:http,https'],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
Page::firstOrCreate(
|
$registerPage($validated['url']);
|
||||||
['url' => $validated['url']],
|
|
||||||
['status' => PageStatusEnum::Discovered],
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->confirmedUrl = $validated['url'];
|
$this->confirmedUrl = $validated['url'];
|
||||||
$this->reset('url');
|
$this->reset('url');
|
||||||
|
|
|
||||||
83
tests/Unit/Actions/RegisterDiscoveredPageActionTest.php
Normal file
83
tests/Unit/Actions/RegisterDiscoveredPageActionTest.php
Normal file
|
|
@ -0,0 +1,83 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Tests\Unit\Actions;
|
||||||
|
|
||||||
|
use App\Actions\RegisterDiscoveredPageAction;
|
||||||
|
use App\Enums\PageStatusEnum;
|
||||||
|
use App\Models\Page;
|
||||||
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||||
|
use Lvl0\FediDiscover\Config\InstanceType;
|
||||||
|
use Lvl0\FediDiscover\Models\Instance;
|
||||||
|
use Tests\TestCase;
|
||||||
|
|
||||||
|
class RegisterDiscoveredPageActionTest extends TestCase
|
||||||
|
{
|
||||||
|
use RefreshDatabase;
|
||||||
|
|
||||||
|
public function test_creates_page_with_url_and_discovered_status(): void
|
||||||
|
{
|
||||||
|
$action = new RegisterDiscoveredPageAction;
|
||||||
|
|
||||||
|
$page = $action('https://example.com/article');
|
||||||
|
|
||||||
|
$this->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,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue