Laravel 13 + Filament 5 admin panel and REST API for a non-profit developer collective, backed by the Pireon OAuth identity server. The public site is a separate, server-rendered application consuming /api/public/v1. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
183 lines
6.5 KiB
PHP
183 lines
6.5 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Database\Seeders;
|
|
|
|
use App\Models\Call;
|
|
use App\Models\Category;
|
|
use App\Models\Client;
|
|
use App\Models\Member;
|
|
use App\Models\Page;
|
|
use App\Models\Project;
|
|
use App\Models\Repository;
|
|
use App\Models\Service;
|
|
use App\Models\Talk;
|
|
use App\Models\Technology;
|
|
use App\Models\Testimonial;
|
|
use Illuminate\Database\Seeder;
|
|
use Illuminate\Support\Collection;
|
|
|
|
class DatabaseSeeder extends Seeder
|
|
{
|
|
public function run(): void
|
|
{
|
|
// Always required: the app cannot authorise anyone without its roles
|
|
// and permissions in place.
|
|
$this->call(RolePermissionSeeder::class);
|
|
|
|
// Sample content only outside production. Real user accounts are
|
|
// never seeded — they are created by the OAuth login flow.
|
|
if (! app()->environment('production')) {
|
|
$this->seedDemoContent();
|
|
}
|
|
}
|
|
|
|
protected function seedDemoContent(): void
|
|
{
|
|
if (Page::query()->exists()) {
|
|
return;
|
|
}
|
|
|
|
$categories = Category::factory()->count(4)->create();
|
|
|
|
Page::factory()
|
|
->count(12)
|
|
->published()
|
|
->recycle($categories)
|
|
->create();
|
|
|
|
Page::factory()->count(4)->draft()->recycle($categories)->create();
|
|
|
|
// A few pages deliberately left translated in the default locale only,
|
|
// so the translation filters and dashboard stat have something to show.
|
|
Page::factory()->count(3)->untranslated()->recycle($categories)->create();
|
|
|
|
$this->seedCollective();
|
|
|
|
$this->command?->info('Seeded demo content for the collective.');
|
|
}
|
|
|
|
/**
|
|
* The collective's own content: who we are, what we build, what we use and
|
|
* what we need.
|
|
*/
|
|
protected function seedCollective(): void
|
|
{
|
|
$technologies = Technology::factory()->count(12)->create();
|
|
$members = Member::factory()->count(8)->create();
|
|
|
|
Member::factory()->count(2)->founder()->create();
|
|
Member::factory()->count(2)->past()->create();
|
|
|
|
Member::all()->each(
|
|
fn (Member $member) => $member->technologies()->sync(
|
|
$technologies->random(rand(2, 5))->pluck('id'),
|
|
),
|
|
);
|
|
|
|
$projects = Project::factory()
|
|
->count(6)
|
|
->published()
|
|
->create()
|
|
->each(function (Project $project) use ($technologies, $members): void {
|
|
$project->technologies()->sync($technologies->random(rand(2, 5))->pluck('id'));
|
|
$project->members()->sync(
|
|
$members->random(rand(1, 3))->mapWithKeys(fn (Member $m) => [
|
|
$m->id => ['role' => fake()->randomElement(['dev', 'diseño', 'infra'])],
|
|
]),
|
|
);
|
|
$project->update(['lead_member_id' => $members->random()->id]);
|
|
|
|
Repository::factory()->for($project)->create();
|
|
});
|
|
|
|
// One archived project with a write-up, and one unpublished, so the
|
|
// public API's filtering has something real to exclude.
|
|
Project::factory()->withPostmortem()->published()->create();
|
|
Project::factory()->draft()->create();
|
|
|
|
$this->seedShowcase($projects, $members, $technologies);
|
|
|
|
// Open calls, some attached to a project and some standalone.
|
|
Call::factory()
|
|
->count(4)
|
|
->create(['project_id' => $projects->random()->id])
|
|
->each(fn (Call $call) => $call->technologies()->sync(
|
|
$technologies->random(rand(1, 3))->pluck('id'),
|
|
));
|
|
|
|
Call::factory()->count(2)->create(['project_id' => null]);
|
|
Call::factory()->closed()->create(['project_id' => null]);
|
|
|
|
// Mirrored issues, so the "good first issues" endpoint is not empty
|
|
// before anyone has configured a real git token.
|
|
Repository::all()->each(function (Repository $repository): void {
|
|
foreach (range(1, rand(1, 4)) as $number) {
|
|
$repository->issues()->create([
|
|
'number' => $number,
|
|
'title' => fake()->sentence(6),
|
|
'html_url' => "{$repository->html_url}/issues/{$number}",
|
|
'labels' => ['good first issue'],
|
|
'is_good_first_issue' => true,
|
|
'is_help_wanted' => fake()->boolean(),
|
|
'author' => 'maintainer',
|
|
'assignee' => fake()->boolean(25) ? 'someone' : null,
|
|
'comments' => rand(0, 8),
|
|
'issue_created_at' => now()->subDays(rand(1, 90)),
|
|
'issue_updated_at' => now()->subDays(rand(0, 10)),
|
|
]);
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* What the landing page is built from.
|
|
*
|
|
* Without these a fresh install has projects and members but nothing to
|
|
* compose a front page out of, which makes it impossible to tell whether
|
|
* the frontend works.
|
|
*
|
|
* @param Collection<int, Project> $projects
|
|
* @param Collection<int, Member> $members
|
|
* @param Collection<int, Technology> $technologies
|
|
*/
|
|
protected function seedShowcase($projects, $members, $technologies): void
|
|
{
|
|
// Organisations the work was for, each with at least one project so
|
|
// the wall of logos is not empty.
|
|
$clients = Client::factory()->count(4)->create();
|
|
|
|
$projects->each(fn (Project $project) => $project->update([
|
|
'client_id' => $clients->random()->id,
|
|
]));
|
|
|
|
$services = Service::factory()->count(4)->create();
|
|
|
|
$services->each(function (Service $service) use ($projects, $technologies): void {
|
|
$service->technologies()->sync($technologies->random(rand(2, 4))->pluck('id'));
|
|
$service->projects()->sync($projects->random(rand(1, 3))->pluck('id'));
|
|
});
|
|
|
|
// One published service with nothing behind it, so the health check
|
|
// that calls that out has something real to find.
|
|
Service::factory()->create(['is_featured' => true]);
|
|
|
|
Service::factory()->draft()->create();
|
|
|
|
Testimonial::factory()->count(3)->create([
|
|
'client_id' => $clients->random()->id,
|
|
]);
|
|
|
|
Testimonial::factory()->create(['service_id' => $services->random()->id]);
|
|
Testimonial::factory()->create(['project_id' => $projects->random()->id]);
|
|
|
|
Talk::factory()->count(5)->create([
|
|
'member_id' => $members->random()->id,
|
|
]);
|
|
|
|
// And one nobody is credited with, for the same reason.
|
|
Talk::factory()->create(['member_id' => null]);
|
|
}
|
|
}
|