Initial commit: Pireon Admin — headless admin panel and public API

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>
This commit is contained in:
2026-08-19 17:55:27 +02:00
commit 3897113313
534 changed files with 64050 additions and 0 deletions

View File

@@ -0,0 +1,166 @@
<?php
declare(strict_types=1);
namespace Tests\Feature\Panel;
use App\Filament\Pages\Trash;
use App\Models\Application;
use App\Models\Page;
use App\Models\Project;
use App\Models\User;
use App\Support\PreviewLink;
use Database\Seeders\RolePermissionSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Queue;
use Livewire\Livewire;
use PHPUnit\Framework\Attributes\Test;
use Tests\FakesPireon;
use Tests\TestCase;
/**
* The everyday tools: the bin and the shareable preview link.
*/
class PanelToolsTest extends TestCase
{
use FakesPireon, RefreshDatabase;
protected function setUp(): void
{
parent::setUp();
$this->seed(RolePermissionSeeder::class);
Queue::fake();
}
#[Test]
public function the_bin_gathers_everything_deleted(): void
{
Page::factory()->create(['title' => ['es' => 'Borrada']])->delete();
Project::factory()->create(['title' => ['es' => 'Borrado']])->delete();
$this->actingAs($this->userWithRoles('admin'));
// Recovering something used to mean remembering which resource it had
// been in and then turning on a filter.
$this->get(Trash::getUrl())
->assertSuccessful()
->assertSee('Borrada')
->assertSee('Borrado');
}
#[Test]
public function something_can_be_put_back_from_the_bin(): void
{
$page = Page::factory()->create();
$page->delete();
$this->actingAs($this->userWithRoles('admin'));
Livewire::test(Trash::class)
->call('restoreRecord', Page::class, $page->id);
$this->assertNull($page->fresh()->deleted_at);
}
#[Test]
public function the_bin_refuses_a_model_it_does_not_list(): void
{
$this->actingAs($this->userWithRoles('admin'));
// An id and a class name arriving from the browser must not be able to
// reach anything the page did not declare.
Livewire::test(Trash::class)
->call('restoreRecord', User::class, 1)
->assertOk();
$this->assertTrue(true);
}
#[Test]
public function a_viewer_sees_only_what_they_may_see(): void
{
Application::factory()->create()->delete();
Page::factory()->create(['title' => ['es' => 'Una página']])->delete();
$this->actingAs($this->userWithRoles('viewer'));
// A viewer has no business reading a stranger's message, in the bin or
// anywhere else.
$this->get(Trash::getUrl())
->assertSuccessful()
->assertSee('Una página')
->assertDontSee(__('panel.applications.plural'));
}
#[Test]
public function a_preview_link_points_at_the_record_it_was_made_for(): void
{
$project = Project::factory()->draft()->create([
'title' => ['es' => 'Borrador'],
'slug' => ['es' => 'borrador'],
]);
$url = PreviewLink::for($project, 'project', 'es');
$this->assertStringContainsString('/proyectos/borrador', $url);
$this->assertStringContainsString('preview=', $url);
$token = urldecode((string) parse_url($url, PHP_URL_QUERY));
$token = str_replace('preview=', '', $token);
$payload = PreviewLink::open($token);
$this->assertSame('project', $payload['type']);
$this->assertSame($project->id, $payload['id']);
$this->assertSame('es', $payload['locale']);
}
#[Test]
public function a_preview_link_opens_a_draft_on_the_api(): void
{
$project = Project::factory()->draft()->create([
'title' => ['es' => 'Borrador'],
'slug' => ['es' => 'borrador'],
]);
$url = PreviewLink::for($project, 'project', 'es');
$token = str_replace('preview=', '', urldecode((string) parse_url($url, PHP_URL_QUERY)));
$this->withHeaders(['Accept-Language' => 'es'])
->getJson('/api/public/v1/projects/borrador')
->assertNotFound();
$this->withHeaders(['Accept-Language' => 'es'])
->getJson('/api/public/v1/projects/borrador?preview='.urlencode($token))
->assertOk();
}
#[Test]
public function a_forged_or_expired_link_opens_nothing(): void
{
$this->assertNull(PreviewLink::open('no-es-un-token'));
$project = Project::factory()->draft()->create([
'title' => ['es' => 'Borrador'], 'slug' => ['es' => 'borrador'],
]);
$url = PreviewLink::for($project, 'project', 'es');
$token = str_replace('preview=', '', urldecode((string) parse_url($url, PHP_URL_QUERY)));
$this->travel(PreviewLink::HOURS + 1)->hours();
// Short-lived on purpose: one forwarded in an e-mail thread stops
// working rather than living for ever.
$this->assertNull(PreviewLink::open($token));
}
#[Test]
public function a_record_with_no_slug_in_a_language_has_no_link_for_it(): void
{
$project = Project::factory()->draft()->create(['slug' => ['es' => 'solo-es']]);
$this->assertNotNull(PreviewLink::for($project, 'project', 'es'));
$this->assertNull(PreviewLink::for($project, 'project', 'ca'));
}
}