- Fix probundle exports missing images (double slides/ prefix in storage path) - Replace manual ZipArchive with PresentationBundle + ProBundleWriter from parser plugin - Add per-agenda-item download route and buttons for songs and slide items - Remove text layer from image-only slides in .pro generation - Fix image conversion: upscale small images, black bars on 2 sides max (contain) - Add upload warnings for non-16:9 and sub-1920x1080 images (German, non-blocking) - Update SlideFactory and all tests to use slides/ prefix in stored_filename - Add 11 new tests (agenda download, image conversion, upload warnings)
140 lines
4.6 KiB
PHP
140 lines
4.6 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature;
|
|
|
|
use App\Models\Service;
|
|
use App\Models\Slide;
|
|
use App\Models\User;
|
|
use Illuminate\Foundation\Testing\Concerns\InteractsWithAuthentication;
|
|
use Illuminate\Foundation\Testing\Concerns\MakesHttpRequests;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Support\Facades\Storage;
|
|
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
|
use Tests\TestCase;
|
|
use ZipArchive;
|
|
|
|
final class ProBundleExportTest extends TestCase
|
|
{
|
|
use InteractsWithAuthentication;
|
|
use MakesHttpRequests;
|
|
use RefreshDatabase;
|
|
|
|
public function test_probundle_enthaelt_pro_datei_und_bilder(): void
|
|
{
|
|
Storage::fake('public');
|
|
|
|
$user = User::factory()->create();
|
|
$service = Service::factory()->create();
|
|
|
|
$filenames = [
|
|
'info-1.jpg',
|
|
'info-2.jpg',
|
|
'info-3.jpg',
|
|
];
|
|
|
|
foreach ($filenames as $index => $filename) {
|
|
Storage::disk('public')->put('slides/'.$filename, 'fake-image-content-'.$index);
|
|
|
|
Slide::factory()->create([
|
|
'service_id' => $service->id,
|
|
'type' => 'information',
|
|
'stored_filename' => 'slides/'.$filename,
|
|
'original_filename' => 'Original '.$filename,
|
|
'sort_order' => $index,
|
|
]);
|
|
}
|
|
|
|
$response = $this->actingAs($user)->get(route('services.download-bundle', [
|
|
'service' => $service,
|
|
'blockType' => 'information',
|
|
]));
|
|
|
|
$response->assertOk();
|
|
$response->assertHeader('content-type', 'application/zip');
|
|
|
|
$baseResponse = $response->baseResponse;
|
|
if (! $baseResponse instanceof BinaryFileResponse) {
|
|
$this->fail('Es wurde keine Dateiantwort zurückgegeben.');
|
|
}
|
|
|
|
$copiedPath = sys_get_temp_dir().'/probundle-test-'.uniqid().'.probundle';
|
|
copy($baseResponse->getFile()->getPathname(), $copiedPath);
|
|
|
|
$zip = new ZipArchive;
|
|
$openResult = $zip->open($copiedPath);
|
|
|
|
$this->assertTrue($openResult === true);
|
|
$this->assertSame(4, $zip->numFiles);
|
|
|
|
$names = [];
|
|
for ($i = 0; $i < $zip->numFiles; $i++) {
|
|
$name = $zip->getNameIndex($i);
|
|
if ($name !== false) {
|
|
$names[] = $name;
|
|
}
|
|
}
|
|
|
|
$proEntry = array_values(array_filter($names, fn (string $n) => str_ends_with($n, '.pro')));
|
|
$this->assertCount(1, $proEntry, '.probundle muss genau eine .pro Datei enthalten');
|
|
$this->assertContains('info-1.jpg', $names);
|
|
$this->assertContains('info-2.jpg', $names);
|
|
$this->assertContains('info-3.jpg', $names);
|
|
|
|
foreach ($filenames as $index => $filename) {
|
|
$content = $zip->getFromName($filename);
|
|
$this->assertSame('fake-image-content-'.$index, $content, "Bildinhalt von {$filename} muss korrekt sein");
|
|
}
|
|
|
|
$proContent = $zip->getFromName($proEntry[0]);
|
|
$this->assertNotFalse($proContent, '.pro Eintrag muss existieren');
|
|
$this->assertGreaterThan(0, strlen($proContent), '.pro Eintrag darf nicht leer sein');
|
|
|
|
$zip->close();
|
|
@unlink($copiedPath);
|
|
}
|
|
|
|
public function test_ungueltiger_block_type_liefert_422(): void
|
|
{
|
|
$user = User::factory()->create();
|
|
$service = Service::factory()->create();
|
|
|
|
$response = $this->actingAs($user)->getJson(route('services.download-bundle', [
|
|
'service' => $service,
|
|
'blockType' => 'ungueltig',
|
|
]));
|
|
|
|
$response->assertStatus(422);
|
|
}
|
|
|
|
public function test_probundle_ohne_slides_enthaelt_nur_pro_datei(): void
|
|
{
|
|
$user = User::factory()->create();
|
|
$service = Service::factory()->create();
|
|
|
|
$response = $this->actingAs($user)->get(route('services.download-bundle', [
|
|
'service' => $service,
|
|
'blockType' => 'sermon',
|
|
]));
|
|
|
|
$response->assertOk();
|
|
|
|
$baseResponse = $response->baseResponse;
|
|
if (! $baseResponse instanceof BinaryFileResponse) {
|
|
$this->fail('Es wurde keine Dateiantwort zurückgegeben.');
|
|
}
|
|
|
|
$copiedPath = sys_get_temp_dir().'/probundle-empty-test-'.uniqid().'.probundle';
|
|
copy($baseResponse->getFile()->getPathname(), $copiedPath);
|
|
|
|
$zip = new ZipArchive;
|
|
$openResult = $zip->open($copiedPath);
|
|
|
|
$this->assertTrue($openResult === true);
|
|
$this->assertSame(1, $zip->numFiles);
|
|
$this->assertTrue(str_ends_with($zip->getNameIndex(0), '.pro'), 'Einziger Eintrag muss .pro Datei sein');
|
|
$zip->close();
|
|
|
|
@unlink($copiedPath);
|
|
}
|
|
}
|