lemmyAuthService = $lemmyAuthService; } public function mount(): void { // Check for existing platform account $account = PlatformAccount::where('is_active', true)->first(); if ($account) { $this->existingAccount = [ 'id' => $account->id, 'username' => $account->username, 'instance_url' => $account->instance_url, ]; } // Pre-fill feed form if exists $feed = Feed::where('is_active', true)->first(); if ($feed) { $this->feedName = $feed->name; $this->feedProvider = $feed->provider ?? 'vrt'; $this->feedLanguageId = $feed->language_id; $this->feedDescription = $feed->description ?? ''; } // Pre-fill channel form if exists $channel = PlatformChannel::where('is_active', true)->first(); if ($channel) { $this->channelName = $channel->name; $this->platformInstanceId = $channel->platform_instance_id; $this->channelLanguageId = $channel->language_id; $this->channelDescription = $channel->description ?? ''; } // Pre-fill route form if exists $route = Route::where('is_active', true)->first(); if ($route) { $this->routeFeedId = $route->feed_id; $this->routeChannelId = $route->platform_channel_id; $this->routePriority = $route->priority; } } public function goToStep(int $step): void { $this->step = $step; $this->errors = []; } public function nextStep(): void { $this->step++; $this->errors = []; } public function previousStep(): void { if ($this->step > 1) { $this->step--; $this->errors = []; } } public function continueWithExistingAccount(): void { $this->nextStep(); } public function deleteAccount(): void { if ($this->existingAccount) { PlatformAccount::destroy($this->existingAccount['id']); $this->existingAccount = null; } } public function createPlatformAccount(): void { $this->errors = []; $this->isLoading = true; $this->validate([ 'instanceUrl' => '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|min:6', ], [ 'instanceUrl.regex' => 'Please enter a valid domain name (e.g., lemmy.world, belgae.social)', ]); $fullInstanceUrl = 'https://' . $this->instanceUrl; try { // Create or get platform instance $platformInstance = PlatformInstance::firstOrCreate([ 'url' => $fullInstanceUrl, 'platform' => 'lemmy', ], [ 'name' => ucfirst($this->instanceUrl), 'is_active' => true, ]); // Authenticate with Lemmy API $authResponse = $this->lemmyAuthService->authenticate( $fullInstanceUrl, $this->username, $this->password ); // Create platform account $platformAccount = PlatformAccount::create([ 'platform' => 'lemmy', 'instance_url' => $fullInstanceUrl, 'username' => $this->username, 'password' => Crypt::encryptString($this->password), 'settings' => [ 'display_name' => $authResponse['person_view']['person']['display_name'] ?? null, 'description' => $authResponse['person_view']['person']['bio'] ?? null, 'person_id' => $authResponse['person_view']['person']['id'] ?? null, 'platform_instance_id' => $platformInstance->id, 'api_token' => $authResponse['jwt'] ?? null, ], 'is_active' => true, 'status' => 'active', ]); $this->existingAccount = [ 'id' => $platformAccount->id, 'username' => $platformAccount->username, 'instance_url' => $platformAccount->instance_url, ]; $this->nextStep(); } catch (\App\Exceptions\PlatformAuthException $e) { if (str_contains($e->getMessage(), 'Rate limited by')) { $this->errors['general'] = $e->getMessage(); } else { $this->errors['general'] = 'Invalid username or password. Please check your credentials and try again.'; } } catch (\Exception $e) { $this->errors['general'] = 'Unable to connect to the Lemmy instance. Please check the URL and try again.'; } finally { $this->isLoading = false; } } public function createFeed(): void { $this->errors = []; $this->isLoading = true; $this->validate([ 'feedName' => 'required|string|max:255', 'feedProvider' => 'required|in:belga,vrt', 'feedLanguageId' => 'required|exists:languages,id', 'feedDescription' => 'nullable|string|max:1000', ]); try { // Map provider to URL $url = $this->feedProvider === 'vrt' ? 'https://www.vrt.be/vrtnws/en/' : 'https://www.belganewsagency.eu/'; Feed::firstOrCreate( ['url' => $url], [ 'name' => $this->feedName, 'type' => 'website', 'provider' => $this->feedProvider, 'language_id' => $this->feedLanguageId, 'description' => $this->feedDescription ?: null, 'is_active' => true, ] ); $this->nextStep(); } catch (\Exception $e) { $this->errors['general'] = 'Failed to create feed. Please try again.'; } finally { $this->isLoading = false; } } public function createChannel(): void { $this->errors = []; $this->isLoading = true; $this->validate([ 'channelName' => 'required|string|max:255', 'platformInstanceId' => 'required|exists:platform_instances,id', 'channelLanguageId' => 'required|exists:languages,id', 'channelDescription' => 'nullable|string|max:1000', ]); try { $platformInstance = PlatformInstance::findOrFail($this->platformInstanceId); // Check for active platform accounts $activeAccounts = PlatformAccount::where('instance_url', $platformInstance->url) ->where('is_active', true) ->get(); if ($activeAccounts->isEmpty()) { $this->errors['general'] = 'No active platform accounts found for this instance. Please create a platform account first.'; $this->isLoading = false; return; } $channel = PlatformChannel::create([ 'platform_instance_id' => $this->platformInstanceId, 'channel_id' => $this->channelName, 'name' => $this->channelName, 'display_name' => ucfirst($this->channelName), 'description' => $this->channelDescription ?: null, 'language_id' => $this->channelLanguageId, 'is_active' => true, ]); // Attach first active account $channel->platformAccounts()->attach($activeAccounts->first()->id, [ 'is_active' => true, 'priority' => 1, 'created_at' => now(), 'updated_at' => now(), ]); $this->nextStep(); } catch (\Exception $e) { $this->errors['general'] = 'Failed to create channel. Please try again.'; } finally { $this->isLoading = false; } } public function createRoute(): void { $this->errors = []; $this->isLoading = true; $this->validate([ 'routeFeedId' => 'required|exists:feeds,id', 'routeChannelId' => 'required|exists:platform_channels,id', 'routePriority' => 'nullable|integer|min:1|max:100', ]); try { Route::create([ 'feed_id' => $this->routeFeedId, 'platform_channel_id' => $this->routeChannelId, 'priority' => $this->routePriority, 'is_active' => true, ]); // Trigger article discovery ArticleDiscoveryJob::dispatch(); $this->nextStep(); } catch (\Exception $e) { $this->errors['general'] = 'Failed to create route. Please try again.'; } finally { $this->isLoading = false; } } public function completeOnboarding(): void { Setting::updateOrCreate( ['key' => 'onboarding_completed'], ['value' => now()->toIso8601String()] ); app(OnboardingService::class)->clearCache(); $this->redirect(route('dashboard')); } public function render() { $languages = Language::where('is_active', true)->orderBy('name')->get(); $platformInstances = PlatformInstance::where('is_active', true)->orderBy('name')->get(); $feeds = Feed::where('is_active', true)->orderBy('name')->get(); $channels = PlatformChannel::where('is_active', true)->orderBy('name')->get(); $feedProviders = collect(config('feed.providers', [])) ->filter(fn($provider) => $provider['is_active'] ?? false) ->values(); return view('livewire.onboarding', [ 'languages' => $languages, 'platformInstances' => $platformInstances, 'feeds' => $feeds, 'channels' => $channels, 'feedProviders' => $feedProviders, ])->layout('layouts.guest'); } }