feat(service): add image columns and overrides

Enable storage-backed key visuals and background images plus service-specific moderator and preacher name overrides.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
Thorsten Bus 2026-05-31 00:01:24 +02:00
parent 73a523d0e1
commit 6061e4c4dd
3 changed files with 96 additions and 0 deletions

View file

@ -17,7 +17,11 @@ class Service extends Model
'title',
'date',
'preacher_name',
'preacher_name_override',
'beamer_tech_name',
'key_visual_filename',
'background_filename',
'moderator_name',
'finalized_at',
'last_synced_at',
'cts_data',
@ -45,6 +49,16 @@ public function slides(): HasMany
return $this->hasMany(Slide::class);
}
protected function keyVisualUrl(): Attribute
{
return Attribute::get(fn () => $this->key_visual_filename ? '/storage/'.$this->key_visual_filename : null);
}
protected function backgroundUrl(): Attribute
{
return Attribute::get(fn () => $this->background_filename ? '/storage/'.$this->background_filename : null);
}
public function agendaItems(): HasMany
{
return $this->hasMany(ServiceAgendaItem::class)->orderBy('sort_order');

View file

@ -0,0 +1,30 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('services', function (Blueprint $table) {
$table->string('key_visual_filename')->nullable()->after('beamer_tech_name');
$table->string('background_filename')->nullable()->after('key_visual_filename');
$table->string('moderator_name')->nullable()->after('background_filename');
$table->string('preacher_name_override')->nullable()->after('moderator_name');
});
}
public function down(): void
{
Schema::table('services', function (Blueprint $table) {
$table->dropColumn([
'key_visual_filename',
'background_filename',
'moderator_name',
'preacher_name_override',
]);
});
}
};

View file

@ -0,0 +1,52 @@
<?php
use App\Models\Service;
use Illuminate\Support\Facades\Schema;
beforeEach(function () {
// Migration rollback is validated via schema assertions; run `ddev exec php artisan migrate:rollback --step=1` manually if needed.
});
test('key visual url returns storage path when filename exists', function () {
$service = Service::factory()->create([
'key_visual_filename' => 'slides/a.jpg',
]);
expect($service->keyVisualUrl)->toBe('/storage/slides/a.jpg');
});
test('key visual url returns null when filename is missing', function () {
$service = Service::factory()->create([
'key_visual_filename' => null,
]);
expect($service->keyVisualUrl)->toBeNull();
});
test('service fillable persists image and name override columns', function () {
$service = Service::factory()->create();
$service->fill([
'key_visual_filename' => 'slides/key.jpg',
'background_filename' => 'slides/background.jpg',
'moderator_name' => 'Max Mustermann',
'preacher_name_override' => 'Lisa Beispiel',
]);
$service->save();
$fresh = $service->fresh();
expect($fresh->key_visual_filename)->toBe('slides/key.jpg')
->and($fresh->background_filename)->toBe('slides/background.jpg')
->and($fresh->moderator_name)->toBe('Max Mustermann')
->and($fresh->preacher_name_override)->toBe('Lisa Beispiel')
->and($fresh->backgroundUrl)->toBe('/storage/slides/background.jpg');
});
test('services table has the new image and override columns', function () {
expect(Schema::hasColumn('services', 'key_visual_filename'))->toBeTrue()
->and(Schema::hasColumn('services', 'background_filename'))->toBeTrue()
->and(Schema::hasColumn('services', 'moderator_name'))->toBeTrue()
->and(Schema::hasColumn('services', 'preacher_name_override'))->toBeTrue();
});