Backend: Medien-Typen, Sprachnotizen, Event-Felder und Sync-Härtung
- Event-Medien tragen Typ (image/video/audio), Dauer und Notiz; Videos bekommen ein Poster, Audio wird per ffmpeg nach AAC (audio/mp4) gewandelt, Originale werden mit Range-Unterstützung gestreamt. - Upload nimmt eine Notiz (caption) direkt mit, PATCH ändert sie später. - Neue Event-Felder: Zeitraum (end_date), Kategorie, Personen, Meilenstein. Regeln zentral in EventFields, damit CRUD und Sync gleich prüfen. - Titel darf leer sein: ein Event entsteht mit dem ersten Eintrag. - Artisan-Befehl media:transcode-voice-notes wandelt alte WebM/Ogg-Notizen, die Safari nicht abspielen kann. - Login-Throttling, Settings-Validierung, Sync-Fehlercodes ohne Rohtext. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
f79dcb9928
commit
b262a6771f
59 changed files with 11879 additions and 197 deletions
82
backend/tests/Feature/Console/ImportLifelineImagesTest.php
Normal file
82
backend/tests/Feature/Console/ImportLifelineImagesTest.php
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
<?php
|
||||
|
||||
use App\Models\Event;
|
||||
use App\Models\User;
|
||||
use Database\Seeders\LifelineSeeder;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
beforeEach(function () {
|
||||
Storage::fake('local');
|
||||
|
||||
$this->imageDirectory = sys_get_temp_dir().'/lifeline-images-test-'.uniqid();
|
||||
File::ensureDirectoryExists($this->imageDirectory);
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
File::deleteDirectory($this->imageDirectory);
|
||||
});
|
||||
|
||||
function fakeLifelineImage(string $path): void
|
||||
{
|
||||
$image = imagecreatetruecolor(64, 48);
|
||||
imagefill($image, 0, 0, imagecolorallocate($image, 200, 160, 90));
|
||||
imagepng($image, $path);
|
||||
imagedestroy($image);
|
||||
}
|
||||
|
||||
test('import attaches key images to seeded lifeline events by age and month', function () {
|
||||
$this->seed(LifelineSeeder::class);
|
||||
|
||||
foreach (['04-07', '10-02'] as $slug) {
|
||||
fakeLifelineImage("{$this->imageDirectory}/{$slug}.png");
|
||||
}
|
||||
|
||||
$this->artisan('lifelines:import-images', ['handle' => 'bruno', '--from' => $this->imageDirectory])
|
||||
->expectsOutputToContain('Imported 2, skipped 0')
|
||||
->assertSuccessful();
|
||||
|
||||
$bruno = User::query()->where('email', 'bruno@thats-me.app')->firstOrFail();
|
||||
$event = Event::query()
|
||||
->where('client_id', LifelineSeeder::clientId('bruno@thats-me.app', 4, 7))
|
||||
->firstOrFail();
|
||||
|
||||
$media = $event->media()->where('collection', 'key_image')->firstOrFail();
|
||||
|
||||
expect($event->image)->toBe("/event-media/{$media->id}/thumb")
|
||||
->and($media->user_id)->toBe($bruno->id)
|
||||
->and($media->mime_type)->toBe('image/jpeg');
|
||||
|
||||
Storage::disk('local')->assertExists([$media->path, $media->preview_path, $media->thumbnail_path]);
|
||||
});
|
||||
|
||||
test('import skips events that already have a key image unless forced', function () {
|
||||
$this->seed(LifelineSeeder::class);
|
||||
|
||||
fakeLifelineImage("{$this->imageDirectory}/04-07.png");
|
||||
|
||||
$this->artisan('lifelines:import-images', ['handle' => 'bruno', '--from' => $this->imageDirectory])->assertSuccessful();
|
||||
$this->artisan('lifelines:import-images', ['handle' => 'bruno', '--from' => $this->imageDirectory])
|
||||
->expectsOutputToContain('Imported 0, skipped 1')
|
||||
->assertSuccessful();
|
||||
|
||||
$event = Event::query()
|
||||
->where('client_id', LifelineSeeder::clientId('bruno@thats-me.app', 4, 7))
|
||||
->firstOrFail();
|
||||
$firstMedia = $event->media()->where('collection', 'key_image')->firstOrFail();
|
||||
|
||||
$this->artisan('lifelines:import-images', ['handle' => 'bruno', '--from' => $this->imageDirectory, '--force' => true])
|
||||
->expectsOutputToContain('Imported 1')
|
||||
->assertSuccessful();
|
||||
|
||||
expect($event->media()->where('collection', 'key_image')->count())->toBe(1)
|
||||
->and($event->media()->where('collection', 'key_image')->first()->id)->not->toBe($firstMedia->id);
|
||||
|
||||
Storage::disk('local')->assertMissing($firstMedia->path);
|
||||
});
|
||||
|
||||
test('import fails when the lifeline user is not seeded', function () {
|
||||
$this->artisan('lifelines:import-images', ['handle' => 'bruno', '--from' => $this->imageDirectory])
|
||||
->expectsOutputToContain('not seeded yet')
|
||||
->assertFailed();
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue