diff --git a/app/Actions/CreateChannelAction.php b/app/Actions/CreateChannelAction.php index 3d72ae0..5fdd318 100644 --- a/app/Actions/CreateChannelAction.php +++ b/app/Actions/CreateChannelAction.php @@ -33,6 +33,7 @@ public function execute(string $name, int $platformInstanceId, ?int $languageId 'is_active' => true, ]); + // Attach only the first active account — additional accounts can be linked via the channel management UI $channel->platformAccounts()->attach($activeAccounts->first()->id, [ 'is_active' => true, 'priority' => 1, diff --git a/app/Actions/CreateRouteAction.php b/app/Actions/CreateRouteAction.php index 56711e9..8b9c9ae 100644 --- a/app/Actions/CreateRouteAction.php +++ b/app/Actions/CreateRouteAction.php @@ -6,13 +6,21 @@ class CreateRouteAction { + /** + * Create a route or return an existing one for the same feed+channel pair. + * When a route already exists, the provided priority and isActive values are ignored. + */ public function execute(int $feedId, int $platformChannelId, int $priority = 0, bool $isActive = true): Route { - return Route::create([ - 'feed_id' => $feedId, - 'platform_channel_id' => $platformChannelId, - 'priority' => $priority, - 'is_active' => $isActive, - ]); + return Route::firstOrCreate( + [ + 'feed_id' => $feedId, + 'platform_channel_id' => $platformChannelId, + ], + [ + 'priority' => $priority, + 'is_active' => $isActive, + ] + ); } } diff --git a/app/Http/Controllers/Api/V1/PlatformAccountsController.php b/app/Http/Controllers/Api/V1/PlatformAccountsController.php index 61ea6fa..08b2ce3 100644 --- a/app/Http/Controllers/Api/V1/PlatformAccountsController.php +++ b/app/Http/Controllers/Api/V1/PlatformAccountsController.php @@ -14,9 +14,6 @@ class PlatformAccountsController extends BaseController { - public function __construct( - private readonly CreatePlatformAccountAction $createPlatformAccountAction, - ) {} /** * Display a listing of platform accounts */ @@ -35,13 +32,13 @@ public function index(): JsonResponse /** * Store a newly created platform account */ - public function store(StorePlatformAccountRequest $request): JsonResponse + public function store(StorePlatformAccountRequest $request, CreatePlatformAccountAction $action): JsonResponse { try { $validated = $request->validated(); - $account = $this->createPlatformAccountAction->execute( - $validated['instance_url'], + $account = $action->execute( + $validated['instance_domain'], $validated['username'], $validated['password'], $validated['platform'], diff --git a/app/Http/Requests/StorePlatformAccountRequest.php b/app/Http/Requests/StorePlatformAccountRequest.php index 17dc064..b678482 100644 --- a/app/Http/Requests/StorePlatformAccountRequest.php +++ b/app/Http/Requests/StorePlatformAccountRequest.php @@ -18,7 +18,7 @@ public function rules(): array { return [ 'platform' => 'required|in:lemmy', - 'instance_url' => 'required|string|max:255|regex:/^[a-zA-Z0-9]([a-zA-Z0-9\-\.]*[a-zA-Z0-9])?$/', + 'instance_domain' => 'required|string|max:255|regex:/^[a-zA-Z0-9]([a-zA-Z0-9\-\.]*[a-zA-Z0-9])?$/', 'username' => 'required|string|max:255', 'password' => 'required|string', ]; @@ -30,7 +30,7 @@ public function rules(): array public function messages(): array { return [ - 'instance_url.regex' => 'Please enter a valid domain name (e.g., lemmy.world, belgae.social)', + 'instance_domain.regex' => 'Please enter a valid domain name (e.g., lemmy.world, belgae.social)', ]; } } diff --git a/app/Livewire/Onboarding.php b/app/Livewire/Onboarding.php index f21e062..c568a43 100644 --- a/app/Livewire/Onboarding.php +++ b/app/Livewire/Onboarding.php @@ -53,7 +53,8 @@ class Onboarding extends Component // State public array $formErrors = []; public bool $isLoading = false; - private ?int $previousChannelLanguageId = null; + #[\Livewire\Attributes\Locked] + public ?int $previousChannelLanguageId = null; protected CreatePlatformAccountAction $createPlatformAccountAction; protected CreateFeedAction $createFeedAction; diff --git a/tests/Feature/Http/Controllers/Api/V1/PlatformAccountsControllerTest.php b/tests/Feature/Http/Controllers/Api/V1/PlatformAccountsControllerTest.php index b68d9b4..511f826 100644 --- a/tests/Feature/Http/Controllers/Api/V1/PlatformAccountsControllerTest.php +++ b/tests/Feature/Http/Controllers/Api/V1/PlatformAccountsControllerTest.php @@ -56,7 +56,7 @@ public function test_store_creates_platform_account_successfully(): void $data = [ 'platform' => 'lemmy', - 'instance_url' => 'lemmy.example.com', + 'instance_domain' => 'lemmy.example.com', 'username' => 'testuser', 'password' => 'testpass123', ]; @@ -94,7 +94,7 @@ public function test_store_validates_required_fields(): void $response = $this->postJson('/api/v1/platform-accounts', []); $response->assertStatus(422) - ->assertJsonValidationErrors(['platform', 'instance_url', 'username', 'password']); + ->assertJsonValidationErrors(['platform', 'instance_domain', 'username', 'password']); } public function test_show_returns_platform_account_successfully(): void diff --git a/tests/Unit/Actions/CreateRouteActionTest.php b/tests/Unit/Actions/CreateRouteActionTest.php index bdc0dc9..0012237 100644 --- a/tests/Unit/Actions/CreateRouteActionTest.php +++ b/tests/Unit/Actions/CreateRouteActionTest.php @@ -59,4 +59,18 @@ public function test_creates_inactive_route(): void $this->assertFalse($route->is_active); } + + public function test_returns_existing_route_for_duplicate_feed_channel_pair(): void + { + $language = Language::factory()->create(); + $feed = Feed::factory()->language($language)->create(); + $channel = PlatformChannel::factory()->create(); + + $first = $this->action->execute($feed->id, $channel->id, 10); + $second = $this->action->execute($feed->id, $channel->id, 99); + + $this->assertEquals($first->id, $second->id); + $this->assertEquals(10, $second->priority); + $this->assertDatabaseCount('routes', 1); + } }