Fix languages and feeds

This commit is contained in:
myrmidex 2025-08-10 21:47:10 +02:00
parent f2947b57c0
commit 1c772e63cb
12 changed files with 171 additions and 20 deletions

View file

@ -57,9 +57,6 @@ public function store(StoreFeedRequest $request): JsonResponse
$validated['url'] = $adapter->getHomepageUrl();
$validated['type'] = 'website';
// Remove provider from validated data as it's not a database column
unset($validated['provider']);
$feed = Feed::create($validated);
return $this->sendResponse(

View file

@ -90,11 +90,17 @@ public function options(): JsonResponse
->orderBy('name')
->get(['id', 'platform_instance_id', 'name', 'display_name', 'description']);
// Get feed providers from config
$feedProviders = collect(config('feed.providers', []))
->filter(fn($provider) => $provider['is_active'])
->values();
return $this->sendResponse([
'languages' => $languages,
'platform_instances' => $platformInstances,
'feeds' => $feeds,
'platform_channels' => $platformChannels,
'feed_providers' => $feedProviders,
], 'Onboarding options retrieved successfully.');
}
@ -215,6 +221,7 @@ public function createFeed(Request $request): JsonResponse
'name' => $validated['name'],
'url' => $url,
'type' => $type,
'provider' => $provider,
'language_id' => $validated['language_id'],
'description' => $validated['description'] ?? null,
'is_active' => true,

View file

@ -15,6 +15,7 @@
* @property string $name
* @property string $url
* @property string $type
* @property string $provider
* @property int $language_id
* @property Language|null $language
* @property string $description
@ -38,6 +39,7 @@ class Feed extends Model
'name',
'url',
'type',
'provider',
'language_id',
'description',
'settings',

View file

@ -3,6 +3,7 @@
namespace App\Services\Factories;
use App\Contracts\ArticleParserInterface;
use App\Models\Feed;
use App\Services\Parsers\VrtArticleParser;
use App\Services\Parsers\BelgaArticleParser;
use Exception;
@ -33,6 +34,25 @@ public static function getParser(string $url): ArticleParserInterface
throw new Exception("No parser found for URL: {$url}");
}
public static function getParserForFeed(Feed $feed, string $parserType = 'article'): ?ArticleParserInterface
{
if (!$feed->provider) {
return null;
}
$providerConfig = config("feed.providers.{$feed->provider}");
if (!$providerConfig || !isset($providerConfig['parsers'][$parserType])) {
return null;
}
$parserClass = $providerConfig['parsers'][$parserType];
if (!class_exists($parserClass)) {
return null;
}
return new $parserClass();
}
/**
* @return array<int, string>
*/

View file

@ -36,10 +36,20 @@ public static function getParser(string $url): HomepageParserInterface
public static function getParserForFeed(Feed $feed): ?HomepageParserInterface
{
try {
return self::getParser($feed->url);
} catch (Exception) {
if (!$feed->provider) {
return null;
}
$providerConfig = config("feed.providers.{$feed->provider}");
if (!$providerConfig || !isset($providerConfig['parsers']['homepage'])) {
return null;
}
$parserClass = $providerConfig['parsers']['homepage'];
if (!class_exists($parserClass)) {
return null;
}
return new $parserClass();
}
}

56
backend/config/feed.php Normal file
View file

@ -0,0 +1,56 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Feed Providers
|--------------------------------------------------------------------------
|
| This array contains the configuration for available feed providers.
| Each provider should have a unique code, display name, description,
| type (website or rss), and active status.
|
*/
'providers' => [
'vrt' => [
'code' => 'vrt',
'name' => 'VRT News',
'description' => 'Belgian public broadcaster news',
'type' => 'website',
'is_active' => true,
'parsers' => [
'homepage' => \App\Services\Parsers\VrtHomepageParserAdapter::class,
'article' => \App\Services\Parsers\VrtArticleParser::class,
'article_page' => \App\Services\Parsers\VrtArticlePageParser::class,
],
],
'belga' => [
'code' => 'belga',
'name' => 'Belga News Agency',
'description' => 'Belgian national news agency',
'type' => 'rss',
'is_active' => true,
'parsers' => [
'homepage' => \App\Services\Parsers\BelgaHomepageParserAdapter::class,
'article' => \App\Services\Parsers\BelgaArticleParser::class,
'article_page' => \App\Services\Parsers\BelgaArticlePageParser::class,
],
],
],
/*
|--------------------------------------------------------------------------
| Default Feed Settings
|--------------------------------------------------------------------------
|
| Default configuration values for feed processing
|
*/
'defaults' => [
'fetch_interval' => 3600, // 1 hour in seconds
'max_articles_per_fetch' => 50,
'article_retention_days' => 30,
],
];

View file

@ -0,0 +1,51 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Supported Languages
|--------------------------------------------------------------------------
|
| This array contains all supported languages in the application.
| Each language has a short_code, display name, native name, and active status.
|
*/
'supported' => [
'en' => [
'short_code' => 'en',
'name' => 'English',
'native_name' => 'English',
'is_active' => true,
],
'nl' => [
'short_code' => 'nl',
'name' => 'Dutch',
'native_name' => 'Nederlands',
'is_active' => true,
],
'fr' => [
'short_code' => 'fr',
'name' => 'French',
'native_name' => 'Français',
'is_active' => true,
],
'de' => [
'short_code' => 'de',
'name' => 'German',
'native_name' => 'Deutsch',
'is_active' => true,
],
],
/*
|--------------------------------------------------------------------------
| Default Language
|--------------------------------------------------------------------------
|
| The default language code when no language is specified
|
*/
'default' => 'en',
];

View file

@ -19,6 +19,7 @@ public function definition(): array
'name' => $this->faker->words(3, true),
'url' => $this->faker->url(),
'type' => $this->faker->randomElement(['website', 'rss']),
'provider' => $this->faker->randomElement(['vrt', 'belga']),
'language_id' => null,
'description' => $this->faker->optional()->sentence(),
'settings' => [],
@ -61,4 +62,20 @@ public function language(Language $language): static
'language_id' => $language->id,
]);
}
public function vrt(): static
{
return $this->state(fn (array $attributes) => [
'provider' => 'vrt',
'url' => 'https://www.vrt.be/vrtnws/en/',
]);
}
public function belga(): static
{
return $this->state(fn (array $attributes) => [
'provider' => 'belga',
'url' => 'https://www.belganewsagency.eu/',
]);
}
}

View file

@ -14,6 +14,7 @@ public function up(): void
$table->string('name'); // "VRT News", "Belga News Agency"
$table->string('url'); // "https://vrt.be" or "https://feeds.example.com/rss.xml"
$table->enum('type', ['website', 'rss']); // Feed type
$table->string('provider'); // Feed provider code (vrt, belga, etc.)
$table->foreignId('language_id')->nullable()->constrained();
$table->text('description')->nullable();
$table->json('settings')->nullable(); // Custom settings per feed type

View file

@ -10,13 +10,7 @@ public function run(): void
{
$this->call([
SettingsSeeder::class,
LanguageSeeder::class,
]);
// Seed languages in local/dev environment only to avoid conflicts in tests
if (app()->environment('local')) {
$this->call([
LanguageSeeder::class,
]);
}
}
}

View file

@ -9,12 +9,7 @@ class LanguageSeeder extends Seeder
{
public function run(): void
{
$languages = [
['short_code' => 'en', 'name' => 'English', 'native_name' => 'English', 'is_active' => true],
['short_code' => 'nl', 'name' => 'Dutch', 'native_name' => 'Nederlands', 'is_active' => true],
['short_code' => 'fr', 'name' => 'French', 'native_name' => 'Français', 'is_active' => true],
['short_code' => 'de', 'name' => 'German', 'native_name' => 'Deutsch', 'is_active' => true],
];
$languages = config('languages.supported', []);
foreach ($languages as $language) {
DB::table('languages')->updateOrInsert(

View file

@ -16,7 +16,7 @@ class FeedTest extends TestCase
public function test_fillable_fields(): void
{
$fillableFields = ['name', 'url', 'type', 'language_id', 'description', 'settings', 'is_active', 'last_fetched_at'];
$fillableFields = ['name', 'url', 'type', 'provider', 'language_id', 'description', 'settings', 'is_active', 'last_fetched_at'];
$feed = new Feed();
$this->assertEquals($fillableFields, $feed->getFillable());
@ -240,6 +240,7 @@ public function test_feed_creation_with_explicit_values(): void
'name' => 'Test Feed',
'url' => 'https://example.com/feed',
'type' => 'rss',
'provider' => 'vrt',
'language_id' => $language->id,
'description' => 'Test description',
'settings' => $settings,