Add factories

This commit is contained in:
myrmidex 2025-07-06 01:35:59 +02:00
parent 626085ed67
commit a1e2f4639b
15 changed files with 339 additions and 6 deletions

View file

@ -7,7 +7,7 @@
/** /**
* @property integer $article_id * @property integer $article_id
* @property integer $community_id * @property integer $platform_channel_id
* @property integer $post_id * @property integer $post_id
* *
* @method static create(array $array) * @method static create(array $array)
@ -16,7 +16,7 @@ class ArticlePublication extends Model
{ {
protected $fillable = [ protected $fillable = [
'article_id', 'article_id',
'community_id', 'platform_channel_id',
'post_id', 'post_id',
'published_at', 'published_at',
'published_by', 'published_by',

View file

@ -2,6 +2,8 @@
namespace App\Models; namespace App\Models;
use Database\Factories\FeedFactory;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\BelongsToMany;
@ -28,6 +30,8 @@
*/ */
class Feed extends Model class Feed extends Model
{ {
/** @use HasFactory<FeedFactory> */
use HasFactory;
private const RECENT_FETCH_THRESHOLD_HOURS = 2; private const RECENT_FETCH_THRESHOLD_HOURS = 2;
private const DAILY_FETCH_THRESHOLD_HOURS = 24; private const DAILY_FETCH_THRESHOLD_HOURS = 24;

View file

@ -2,12 +2,17 @@
namespace App\Models; namespace App\Models;
use Database\Factories\LanguageFactory;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasMany;
class Language extends Model class Language extends Model
{ {
/** @use HasFactory<LanguageFactory> */
use HasFactory;
protected $fillable = [ protected $fillable = [
'short_code', 'short_code',
'name', 'name',

View file

@ -2,6 +2,8 @@
namespace App\Models; namespace App\Models;
use Database\Factories\PlatformAccountFactory;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Collection;
@ -29,6 +31,9 @@
*/ */
class PlatformAccount extends Model class PlatformAccount extends Model
{ {
/** @use HasFactory<PlatformAccountFactory> */
use HasFactory;
protected $fillable = [ protected $fillable = [
'platform', 'platform',
'instance_url', 'instance_url',

View file

@ -2,6 +2,8 @@
namespace App\Models; namespace App\Models;
use Database\Factories\PlatformChannelFactory;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\BelongsToMany;
@ -20,6 +22,9 @@
*/ */
class PlatformChannel extends Model class PlatformChannel extends Model
{ {
/** @use HasFactory<PlatformChannelFactory> */
use HasFactory;
protected $table = 'platform_channels'; protected $table = 'platform_channels';
protected $fillable = [ protected $fillable = [

View file

@ -3,6 +3,8 @@
namespace App\Models; namespace App\Models;
use App\Enums\PlatformEnum; use App\Enums\PlatformEnum;
use Database\Factories\PlatformInstanceFactory;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasMany;
@ -18,6 +20,9 @@
*/ */
class PlatformInstance extends Model class PlatformInstance extends Model
{ {
/** @use HasFactory<PlatformInstanceFactory> */
use HasFactory;
protected $fillable = [ protected $fillable = [
'platform', 'platform',
'url', 'url',

View file

@ -51,7 +51,7 @@ private function publishToChannel(Article $article, array $extractedData, $chann
$publication = ArticlePublication::create([ $publication = ArticlePublication::create([
'article_id' => $article->id, 'article_id' => $article->id,
'post_id' => $postData['post_view']['post']['id'], 'post_id' => $postData['post_view']['post']['id'],
'community_id' => $channel->channel_id, 'platform_channel_id' => $channel->id,
'published_by' => $account->username, 'published_by' => $account->username,
'published_at' => now(), 'published_at' => now(),
'platform' => $channel->platformInstance->platform->value, 'platform' => $channel->platformInstance->platform->value,

View file

@ -0,0 +1,57 @@
<?php
namespace Database\Factories;
use App\Models\Feed;
use App\Models\Language;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends Factory<Feed>
*/
class FeedFactory extends Factory
{
protected $model = Feed::class;
public function definition(): array
{
return [
'name' => $this->faker->words(3, true),
'url' => $this->faker->url(),
'type' => $this->faker->randomElement(['website', 'rss']),
'language_id' => Language::factory(),
'description' => $this->faker->optional()->sentence(),
'settings' => [],
'is_active' => true,
'last_fetched_at' => null,
];
}
public function inactive(): static
{
return $this->state(fn (array $attributes) => [
'is_active' => false,
]);
}
public function website(): static
{
return $this->state(fn (array $attributes) => [
'type' => 'website',
]);
}
public function rss(): static
{
return $this->state(fn (array $attributes) => [
'type' => 'rss',
]);
}
public function recentlyFetched(): static
{
return $this->state(fn (array $attributes) => [
'last_fetched_at' => now()->subHour(),
]);
}
}

View file

@ -0,0 +1,40 @@
<?php
namespace Database\Factories;
use App\Models\Language;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends Factory<Language>
*/
class LanguageFactory extends Factory
{
protected $model = Language::class;
public function definition(): array
{
return [
'short_code' => $this->faker->unique()->languageCode(),
'name' => $this->faker->unique()->word(),
'native_name' => $this->faker->optional()->word(),
'is_active' => true,
];
}
public function inactive(): static
{
return $this->state(fn (array $attributes) => [
'is_active' => false,
]);
}
public function english(): static
{
return $this->state(fn (array $attributes) => [
'short_code' => 'en',
'name' => 'English',
'native_name' => 'English',
]);
}
}

View file

@ -0,0 +1,52 @@
<?php
namespace Database\Factories;
use App\Enums\PlatformEnum;
use App\Models\PlatformAccount;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends Factory<PlatformAccount>
*/
class PlatformAccountFactory extends Factory
{
protected $model = PlatformAccount::class;
public function definition(): array
{
return [
'platform' => PlatformEnum::LEMMY,
'instance_url' => 'https://lemmy.' . $this->faker->domainName(),
'username' => $this->faker->userName(),
'password' => 'test-password',
'settings' => [],
'is_active' => true,
'last_tested_at' => null,
'status' => 'untested',
];
}
public function inactive(): static
{
return $this->state(fn (array $attributes) => [
'is_active' => false,
]);
}
public function tested(): static
{
return $this->state(fn (array $attributes) => [
'last_tested_at' => now()->subHours(2),
'status' => 'working',
]);
}
public function failed(): static
{
return $this->state(fn (array $attributes) => [
'last_tested_at' => now()->subHours(2),
'status' => 'failed',
]);
}
}

View file

@ -0,0 +1,47 @@
<?php
namespace Database\Factories;
use App\Models\Language;
use App\Models\PlatformChannel;
use App\Models\PlatformInstance;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends Factory<PlatformChannel>
*/
class PlatformChannelFactory extends Factory
{
protected $model = PlatformChannel::class;
public function definition(): array
{
return [
'platform_instance_id' => PlatformInstance::factory(),
'channel_id' => $this->faker->slug(2),
'name' => $this->faker->words(2, true),
'display_name' => $this->faker->words(2, true),
'language_id' => Language::factory(),
'description' => $this->faker->optional()->sentence(),
'is_active' => true,
];
}
public function inactive(): static
{
return $this->state(fn (array $attributes) => [
'is_active' => false,
]);
}
public function community(string $name = null): static
{
$communityName = $name ?: $this->faker->word();
return $this->state(fn (array $attributes) => [
'channel_id' => strtolower($communityName),
'name' => $communityName,
'display_name' => ucfirst($communityName),
]);
}
}

View file

@ -0,0 +1,40 @@
<?php
namespace Database\Factories;
use App\Models\PlatformInstance;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends Factory<PlatformInstance>
*/
class PlatformInstanceFactory extends Factory
{
protected $model = PlatformInstance::class;
public function definition(): array
{
return [
'platform' => 'lemmy',
'name' => $this->faker->words(2, true),
'url' => $this->faker->url(),
'is_active' => true,
];
}
public function inactive(): static
{
return $this->state(fn (array $attributes) => [
'is_active' => false,
]);
}
public function lemmy(): static
{
return $this->state(fn (array $attributes) => [
'platform' => 'lemmy',
'name' => 'Lemmy ' . $this->faker->word(),
'url' => 'https://lemmy.' . $this->faker->domainName(),
]);
}
}

View file

@ -12,14 +12,14 @@ public function up(): void
$table->id(); $table->id();
$table->foreignId('article_id')->constrained()->onDelete('cascade'); $table->foreignId('article_id')->constrained()->onDelete('cascade');
$table->string('post_id'); $table->string('post_id');
$table->unsignedBigInteger('community_id'); $table->unsignedBigInteger('platform_channel_id');
$table->string('platform')->default('lemmy'); $table->string('platform')->default('lemmy');
$table->json('publication_data')->nullable(); $table->json('publication_data')->nullable();
$table->timestamp('published_at'); $table->timestamp('published_at');
$table->string('published_by'); $table->string('published_by');
$table->timestamps(); $table->timestamps();
$table->unique(['article_id', 'platform', 'community_id']); $table->unique(['article_id', 'platform', 'platform_channel_id'], 'article_pub_unique');
}); });
} }

View file

@ -16,7 +16,7 @@ public function up(): void
$table->boolean('is_default')->default(false); // Whether this is the default language for this instance $table->boolean('is_default')->default(false); // Whether this is the default language for this instance
$table->timestamps(); $table->timestamps();
$table->unique(['language_id', 'platform_instance_id']); $table->unique(['language_id', 'platform_instance_id'], 'lang_platform_instance_unique');
}); });
} }

73
docker-compose.yml Normal file
View file

@ -0,0 +1,73 @@
services:
laravel.test:
build:
context: ./vendor/laravel/sail/runtimes/8.4
dockerfile: Dockerfile
args:
WWWGROUP: '${WWWGROUP}'
image: sail-8.4/app
extra_hosts:
- 'host.docker.internal:host-gateway'
ports:
- '${APP_PORT:-80}:80'
- '${VITE_PORT:-5173}:${VITE_PORT:-5173}'
environment:
WWWUSER: '${WWWUSER}'
LARAVEL_SAIL: 1
XDEBUG_MODE: '${SAIL_XDEBUG_MODE:-off}'
XDEBUG_CONFIG: '${SAIL_XDEBUG_CONFIG:-client_host=host.docker.internal}'
IGNITION_LOCAL_SITES_PATH: '${PWD}'
volumes:
- '.:/var/www/html'
networks:
- sail
depends_on:
- mysql
- redis
mysql:
image: 'mysql/mysql-server:8.0'
ports:
- '${FORWARD_DB_PORT:-3306}:3306'
environment:
MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}'
MYSQL_ROOT_HOST: '%'
MYSQL_DATABASE: '${DB_DATABASE}'
MYSQL_USER: '${DB_USERNAME}'
MYSQL_PASSWORD: '${DB_PASSWORD}'
MYSQL_ALLOW_EMPTY_PASSWORD: 1
volumes:
- 'sail-mysql:/var/lib/mysql'
- './vendor/laravel/sail/database/mysql/create-testing-database.sh:/docker-entrypoint-initdb.d/10-create-testing-database.sh'
networks:
- sail
healthcheck:
test:
- CMD
- mysqladmin
- ping
- '-p${DB_PASSWORD}'
retries: 3
timeout: 5s
redis:
image: 'redis:alpine'
ports:
- '${FORWARD_REDIS_PORT:-6379}:6379'
volumes:
- 'sail-redis:/data'
networks:
- sail
healthcheck:
test:
- CMD
- redis-cli
- ping
retries: 3
timeout: 5s
networks:
sail:
driver: bridge
volumes:
sail-mysql:
driver: local
sail-redis:
driver: local