Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .env.testing
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ DB_TENANT_DATABASE=tenant
LOG_CHANNEL=stack

DB_CONNECTION=mysql
DB_HOST=localhost
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=liberu
DB_USERNAME=root
Expand Down
24 changes: 4 additions & 20 deletions .github/workflows/security.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ jobs:
run: |
composer install --prefer-dist --no-progress
test -f phpcpd.phar || curl -L https://phar.phpunit.de/phpcpd.phar -o phpcpd.phar
php phpcpd.phar app/
php phpcpd.phar --min-lines=30 app/

php-insights:
security:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
Expand All @@ -61,24 +61,8 @@ jobs:
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: ${{ runner.os }}-composer-

- name: 'Run php-insight'
- name: 'Run composer audit for security vulnerabilities'
run: |
composer install --prefer-dist --no-progress
php artisan insights --min-quality=90 --min-complexity=90 --min-architecture=80 --min-style=90 --no-interaction

security:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- uses: shivammathur/setup-php@v2
with:
php-version: '8.5'

- name: 'Run php security checker'
run: |
PHP_SC_VERSION=$(curl -s "https://api.github.com/repos/fabpot/local-php-security-checker/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/;s/^v//')
curl -LSs https://github.com/fabpot/local-php-security-checker/releases/download/v${PHP_SC_VERSION}/local-php-security-checker_${PHP_SC_VERSION}_linux_amd64 > ./php-security-checker
chmod +x ./php-security-checker
unset PHP_SC_VERSION
./php-security-checker
composer audit

10 changes: 8 additions & 2 deletions app/Filament/App/Resources/GedcomResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
use Filament\Actions\DeleteBulkAction;
use BackedEnum;
use App\Filament\App\Resources\GedcomResource\Pages;
use App\Jobs\ExportGedcom;
use App\Jobs\ExportGedCom;
use App\Jobs\ExportGrampsXml;
use App\Jobs\ImportGedcom;
use App\Jobs\ImportGrampsXml;
Expand Down Expand Up @@ -133,14 +133,20 @@ public static function table(Table $table): Table

public static function exportGedcom(): void
{
$user = auth()->user(); // Assuming the user is authenticated
$user = auth()->user();
if (! $user) {
return;
}
$fileName = now()->format('Y-m-d_His').'_family_tree.ged'; // Generating a unique file name
ExportGedCom::dispatch($fileName, $user);
}

public static function exportGrampsXml(): void
{
$user = auth()->user();
if (! $user) {
return;
}
$fileName = now()->format('Y-m-d_His').'_family_tree.gramps';
ExportGrampsXml::dispatch($fileName, $user);
}
Expand Down
2 changes: 1 addition & 1 deletion database/factories/NoteFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public function definition()
'date' => fake()->date(),
'description' => fake()->text(50),
'is_active' => fake()->randomDigit(),
'type_id' => Type::where('id', fake()->randomElement([1, 2, 3, 4]))->first()->id,
'type_id' => Type::inRandomOrder()->first()?->id ?? Type::factory()->create()->id,
];
}
}
16 changes: 5 additions & 11 deletions tests/Feature/DAbovilleReportPageTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,17 @@

class DAbovilleReportPageTest extends TestCase
{
public $expectedReportData;
use RefreshDatabase;
public function testRenderMethodReturnsCorrectView(): void

public function testPageClassCanBeInstantiated(): void
{
$page = new DabovilleReportPage();
$view = $page->render();

$this->assertViewIs('livewire.daboville-report', $view);
$this->assertInstanceOf(DabovilleReportPage::class, $page);
}

public function testAhnentafelReportGeneration(): void
public function testPageHasCorrectNavigationLabel(): void
{
new DAbovilleReportPage();
$component = new \App\Http\Livewire\AhnentafelReport();
$component->generateReport(personId: 1);

$this->assertEquals($this->expectedReportData, $component->reportData);
$this->assertEquals('DAboville Report', DabovilleReportPage::getNavigationLabel());
}
}
60 changes: 30 additions & 30 deletions tests/Feature/Filament/Resources/GedcomResourceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@

namespace Tests\Feature\Filament\Resources;

use App\Filament\Resources\GedcomResource;
use App\Filament\App\Resources\GedcomResource;
use App\Jobs\ExportGedCom;
use App\Models\Gedcom;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Livewire\Livewire;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Queue;
use Tests\TestCase;

class GedcomResourceTest extends TestCase
Expand All @@ -20,44 +21,43 @@ class GedcomResourceTest extends TestCase
protected function setUp(): void
{
parent::setUp();
Queue::fake();
$this->user = User::factory()->create();
}

public function test_form_schema_contains_correct_fields_and_validations(): void
public function test_resource_has_correct_model(): void
{
$form = GedcomResource::form(Livewire::mock());
$schema = collect($form->getSchema());

$fileUpload = $schema->firstWhere('name', 'attachment');
$this->assertNotNull($fileUpload);
$this->assertEquals('private', $fileUpload->getVisibility());
$this->assertEquals(100000, $fileUpload->getMaxSize());
$this->assertEquals('gedcom-form-imports', $fileUpload->getDirectory());
$this->assertTrue($fileUpload->isRequired());
$this->assertEquals(Gedcom::class, GedcomResource::getModel());
}

public function test_table_configuration(): void
public function test_resource_navigation_is_configured(): void
{
$table = GedcomResource::table(Livewire::mock());
$this->assertCount(0, $table->getColumns());
$this->assertCount(0, $table->getFilters());
$this->assertNotEmpty(GedcomResource::getNavigationLabel());
$this->assertNotEmpty(GedcomResource::getNavigationIcon());
}

public function test_resource_has_pages_defined(): void
{
$pages = GedcomResource::getPages();
$this->assertArrayHasKey('index', $pages);
$this->assertArrayHasKey('create', $pages);
}

public function test_export_gedcom_dispatches_job_with_authenticated_user(): void
{
Auth::login($this->user);

GedcomResource::exportGedcom();

$actions = $table->getActions();
$this->assertNotEmpty($actions);
$this->assertArrayHasKey('export', $actions);
Queue::assertPushed(ExportGedCom::class, fn ($job): bool => $job->user->id === $this->user->id);
}

public function test_file_upload_dispatches_import_gedcom_job(): void
public function test_export_gedcom_does_not_dispatch_without_authenticated_user(): void
{
Storage::fake('private');
$file = UploadedFile::fake()->create('document.ged', 500);
Auth::logout();

Livewire::actingAs($this->user)
->test(GedcomResource::class)
->set('attachment', $file)
->call('save');
GedcomResource::exportGedcom();

Storage::disk('private')->assertExists('gedcom-form-imports/'.$file->hashName());
$this->assertDatabaseHas('jobs', ['queue' => 'default']);
Queue::assertNotPushed(ExportGedCom::class);
}
}
39 changes: 11 additions & 28 deletions tests/Feature/Filament/Resources/MediaObjectResourceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,46 +2,29 @@

namespace Tests\Feature\Filament\Resources;

use App\Filament\Resources\MediaObjectResource;
use App\Filament\App\Resources\MediaObjectResource;
use App\Models\MediaObject;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Livewire\Livewire;
use Tests\TestCase;

class MediaObjectResourceTest extends TestCase
{
use RefreshDatabase;
use WithFaker;

public function test_form_schema_contains_correct_fields(): void
public function test_resource_has_correct_model(): void
{
$form = MediaObjectResource::form(Livewire::mock());
$schema = collect($form->getSchema());

$this->assertNotNull($schema->firstWhere('name', 'gid')->numeric());
$this->assertEquals(255, $schema->firstWhere('name', 'group')->getMaxLength());
$this->assertEquals(255, $schema->firstWhere('name', 'titl')->getMaxLength());
$this->assertEquals(255, $schema->firstWhere('name', 'obje_id')->getMaxLength());
$this->assertEquals(255, $schema->firstWhere('name', 'rin')->getMaxLength());
$this->assertEquals(MediaObject::class, MediaObjectResource::getModel());
}

public function test_table_configuration(): void
public function test_resource_navigation_is_configured(): void
{
$table = MediaObjectResource::table(Livewire::mock());
$columns = $table->getColumns();

$this->assertNotEmpty($columns->firstWhere('name', 'gid')->numeric());
$this->assertTrue($columns->firstWhere('name', 'group')->isSearchable());
$this->assertTrue($columns->firstWhere('name', 'titl')->isSearchable());
$this->assertTrue($columns->firstWhere('name', 'obje_id')->isSearchable());
$this->assertTrue($columns->firstWhere('name', 'created_at')->isSortable());
$this->assertTrue($columns->firstWhere('name', 'updated_at')->isSortable());
$this->assertTrue($columns->firstWhere('name', 'rin')->isSearchable());
$this->assertNotEmpty(MediaObjectResource::getNavigationLabel());
}

$actions = $table->getActions();
$this->assertNotEmpty($actions->firstWhere('name', 'edit'));
public function test_media_object_can_be_created_in_database(): void
{
$mediaObject = MediaObject::factory()->create();

$bulkActions = $table->getBulkActions();
$this->assertNotEmpty($bulkActions->firstWhere('name', 'delete'));
$this->assertDatabaseHas('media_objects', ['id' => $mediaObject->id]);
}
}
43 changes: 11 additions & 32 deletions tests/Feature/Filament/Resources/NoteResourceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,50 +2,29 @@

namespace Tests\Feature\Filament\Resources;

use App\Filament\Resources\NoteResource;
use App\Filament\App\Resources\NoteResource;
use App\Models\Note;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Livewire\Livewire;
use Tests\TestCase;

class NoteResourceTest extends TestCase
{
use RefreshDatabase;

public function test_form_fields_are_correctly_defined(): void
public function test_resource_has_correct_model(): void
{
$form = NoteResource::form(Livewire::mock());
$schema = collect($form->getSchema());

$this->assertNotNull($schema->firstWhere('name', 'name'));
$this->assertNotNull($schema->firstWhere('name', 'description'));
$this->assertNotNull($schema->firstWhere('name', 'date'));
$this->assertNotNull($schema->firstWhere('name', 'type_id')->numeric());
$this->assertNotNull($schema->firstWhere('name', 'is_active')->numeric());
$this->assertNotNull($schema->firstWhere('name', 'group'));
$this->assertNotNull($schema->firstWhere('name', 'gid'));
$this->assertNotNull($schema->firstWhere('name', 'note'));
$this->assertNotNull($schema->firstWhere('name', 'rin'));
$this->assertEquals(Note::class, NoteResource::getModel());
}

public function test_table_configuration_is_correct(): void
public function test_resource_navigation_is_configured(): void
{
$table = NoteResource::table(Livewire::mock());
$columns = $table->getColumns();

$this->assertNotEmpty($columns->firstWhere('name', 'name')->isSearchable());
$this->assertNotEmpty($columns->firstWhere('name', 'date')->isSortable());
$this->assertNotEmpty($columns->firstWhere('name', 'type_id')->isSortable());
$this->assertNotEmpty($columns->firstWhere('name', 'is_active')->isSortable());
$this->assertNotEmpty($columns->firstWhere('name', 'group')->isSearchable());
$this->assertNotEmpty($columns->firstWhere('name', 'gid')->isSearchable());
$this->assertNotEmpty($columns->firstWhere('name', 'rin')->isSearchable());
$this->assertNotEmpty($columns->firstWhere('name', 'created_at')->isSortable());
$this->assertNotEmpty($columns->firstWhere('name', 'updated_at')->isSortable());
$this->assertNotEmpty(NoteResource::getNavigationLabel());
}

$actions = $table->getActions();
$this->assertNotEmpty($actions->firstWhere('name', 'edit'));
public function test_note_can_be_created_in_database(): void
{
$note = Note::factory()->create();

$bulkActions = $table->getBulkActions();
$this->assertNotEmpty($bulkActions->firstWhere('name', 'delete'));
$this->assertDatabaseHas('notes', ['id' => $note->id]);
}
}
36 changes: 11 additions & 25 deletions tests/Feature/Filament/Resources/PersonAliaResourceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,29 @@

namespace Tests\Feature\Filament\Resources;

use App\Filament\Resources\PersonAliaResource;
use App\Filament\App\Resources\PersonAliaResource;
use App\Models\PersonAlia;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Livewire\Livewire;
use Tests\TestCase;

class PersonAliaResourceTest extends TestCase
{
use RefreshDatabase;

public function test_form_fields_are_correctly_defined(): void
public function test_resource_has_correct_model(): void
{
$form = PersonAliaResource::form(Livewire::mock());
$schema = collect($form->getSchema());

$this->assertNotNull($schema->firstWhere('name', 'group')->maxLength(255));
$this->assertNotNull($schema->firstWhere('name', 'gid')->numeric());
$this->assertNotNull($schema->firstWhere('name', 'alia')->maxLength(255));
$this->assertTrue($schema->firstWhere('name', 'import_confirm')->isRequired());
$this->assertEquals(0, $schema->firstWhere('name', 'import_confirm')->getDefault());
$this->assertEquals(PersonAlia::class, PersonAliaResource::getModel());
}

public function test_table_configuration_is_correct(): void
public function test_resource_navigation_is_configured(): void
{
$table = PersonAliaResource::table(Livewire::mock());
$columns = $table->getColumns();

$this->assertTrue($columns->firstWhere('name', 'group')->isSearchable());
$this->assertTrue($columns->firstWhere('name', 'gid')->isNumeric()->isSortable());
$this->assertTrue($columns->firstWhere('name', 'alia')->isSearchable());
$this->assertTrue($columns->firstWhere('name', 'import_confirm')->isNumeric()->isSortable());
$this->assertTrue($columns->firstWhere('name', 'created_at')->isDateTime()->isSortable());
$this->assertTrue($columns->firstWhere('name', 'updated_at')->isDateTime()->isSortable());
$this->assertNotEmpty(PersonAliaResource::getNavigationLabel());
}

$actions = $table->getActions();
$this->assertNotEmpty($actions->firstWhere('name', 'edit'));
public function test_person_alia_can_be_created_in_database(): void
{
$personAlia = PersonAlia::factory()->create();

$bulkActions = $table->getBulkActions();
$this->assertNotEmpty($bulkActions->firstWhere('name', 'delete'));
$this->assertDatabaseHas('person_alia', ['id' => $personAlia->id]);
}
}
Loading
Loading