chore(debug): add CTS agenda type discovery command

This commit is contained in:
Thorsten Bus 2026-03-29 11:39:24 +02:00
parent 1f367b6f37
commit 7a71b8b2de
2 changed files with 245 additions and 0 deletions

View file

@ -0,0 +1,88 @@
<?php
namespace App\Console\Commands;
use App\Models\Service;
use App\Services\ChurchToolsService;
use Illuminate\Console\Command;
use Illuminate\Support\Carbon;
use Illuminate\Support\Str;
use Throwable;
class DiscoverAgendaTypes extends Command
{
protected $signature = 'cts:discover-agenda-types';
protected $description = 'Zeigt alle Agenda-Item-Typen eines Services an (Diagnose)';
public function handle(ChurchToolsService $churchToolsService): int
{
try {
$service = Service::where('date', '>=', Carbon::today())
->orderBy('date')
->first();
if (! $service) {
$this->info('Kein bevorstehender Service gefunden.');
return self::SUCCESS;
}
$ctsEventId = (int) $service->cts_event_id;
$agenda = $churchToolsService->syncAgenda($ctsEventId);
if (! $agenda) {
$this->info('Keine Agenda für diesen Service gefunden.');
return self::SUCCESS;
}
$items = $agenda->getItems();
if (empty($items)) {
$this->info('Keine Agenda-Items gefunden.');
return self::SUCCESS;
}
$headers = ['Position', 'Titel', 'Typ', 'Hat Song', 'Vor Event', 'Dauer'];
$rows = [];
$types = [];
foreach ($items as $item) {
$position = $item->getPosition() ?? '-';
$title = Str::limit($item->getTitle() ?? '', 40, '...');
$type = $item->getType() ?? '-';
$hasSong = $item->getSong() !== null ? 'Ja' : 'Nein';
$isBeforeEvent = $item->getIsBeforeEvent() ? 'Ja' : 'Nein';
$duration = $item->getDuration() ?? '-';
$rows[] = [
$position,
$title,
$type,
$hasSong,
$isBeforeEvent,
$duration,
];
if ($type !== '-' && ! in_array($type, $types)) {
$types[] = $type;
}
}
$this->table($headers, $rows);
$this->newLine();
$this->info('Unique Types:');
foreach ($types as $type) {
$this->line(' - '.$type);
}
return self::SUCCESS;
} catch (Throwable $exception) {
$this->error('Fehler beim Abrufen der Agenda: '.$exception->getMessage());
return self::FAILURE;
}
}
}

View file

@ -0,0 +1,157 @@
<?php
namespace Tests\Feature;
use App\Models\Service;
use App\Services\ChurchToolsService;
use CTApi\Models\Events\Event\EventAgenda;
use CTApi\Models\Events\Event\EventAgendaItem;
use CTApi\Models\Events\Song\Song;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Carbon;
use Tests\TestCase;
final class DiscoverAgendaTypesTest extends TestCase
{
use RefreshDatabase;
public function test_command_returns_no_service_found(): void
{
$this->artisan('cts:discover-agenda-types')
->expectsOutput('Kein bevorstehender Service gefunden.')
->assertExitCode(0);
}
public function test_command_displays_agenda_items(): void
{
Carbon::setTestNow('2026-03-29 10:00:00');
Service::factory()->create([
'date' => Carbon::today(),
'cts_event_id' => 123,
]);
$song = new Song;
$song->setId('song-1');
$item1 = new EventAgendaItem;
$item1->setPosition('1');
$item1->setTitle('Welcome Song');
$item1->setType('Song');
$item1->setSong($song);
$item1->setIsBeforeEvent(false);
$item1->setDuration('5:00');
$item2 = new EventAgendaItem;
$item2->setPosition('2');
$item2->setTitle('Announcement');
$item2->setType('Default');
$item2->setIsBeforeEvent(false);
$item2->setDuration(null);
$item3 = new EventAgendaItem;
$item3->setPosition('3');
$item3->setTitle('Sermon');
$item3->setType('Sermon');
$item3->setIsBeforeEvent(false);
$item3->setDuration('30:00');
$agenda = new EventAgenda;
$agenda->setItems([$item1, $item2, $item3]);
$this->app->bind(ChurchToolsService::class, function () use ($agenda) {
return new ChurchToolsService(
agendaFetcher: fn ($id) => $agenda
);
});
$this->artisan('cts:discover-agenda-types')
->expectsTable(
['Position', 'Titel', 'Typ', 'Hat Song', 'Vor Event', 'Dauer'],
[
['1', 'Welcome Song', 'Song', 'Ja', 'Nein', '5:00'],
['2', 'Announcement', 'Default', 'Nein', 'Nein', '-'],
['3', 'Sermon', 'Sermon', 'Nein', 'Nein', '30:00'],
]
)
->expectsOutput('Unique Types:')
->expectsOutput(' - Song')
->expectsOutput(' - Default')
->expectsOutput(' - Sermon')
->assertExitCode(0);
}
public function test_command_handles_missing_agenda(): void
{
Carbon::setTestNow('2026-03-29 10:00:00');
Service::factory()->create([
'date' => Carbon::today(),
'cts_event_id' => 123,
]);
$this->app->bind(ChurchToolsService::class, function () {
return new ChurchToolsService(
agendaFetcher: fn ($id) => null
);
});
$this->artisan('cts:discover-agenda-types')
->expectsOutput('Keine Agenda für diesen Service gefunden.')
->assertExitCode(0);
}
public function test_command_handles_empty_items(): void
{
Carbon::setTestNow('2026-03-29 10:00:00');
Service::factory()->create([
'date' => Carbon::today(),
'cts_event_id' => 123,
]);
$agenda = new EventAgenda;
$agenda->setItems([]);
$this->app->bind(ChurchToolsService::class, function () use ($agenda) {
return new ChurchToolsService(
agendaFetcher: fn ($id) => $agenda
);
});
$this->artisan('cts:discover-agenda-types')
->expectsOutput('Keine Agenda-Items gefunden.')
->assertExitCode(0);
}
public function test_command_truncates_long_titles(): void
{
Carbon::setTestNow('2026-03-29 10:00:00');
Service::factory()->create([
'date' => Carbon::today(),
'cts_event_id' => 123,
]);
$item = new EventAgendaItem;
$item->setPosition('1');
$item->setTitle('This is a very long title that should be truncated to 40 characters');
$item->setType('Song');
$item->setIsBeforeEvent(false);
$item->setDuration('5:00');
$agenda = new EventAgenda;
$agenda->setItems([$item]);
$this->app->bind(ChurchToolsService::class, function () use ($agenda) {
return new ChurchToolsService(
agendaFetcher: fn ($id) => $agenda
);
});
$this->artisan('cts:discover-agenda-types')
->expectsOutput('Unique Types:')
->expectsOutput(' - Song')
->assertExitCode(0);
}
}