Stream-Übersicht aller laufenden Vetos und Matches

/stream zeigt alle aktiven Matches als Karten (Veto mit Map-Board, Match
mit Live-Stand und Serie), dazu offene Lobbys und Ergebnisse. Raster passt
sich der Anzahl an, ab 7 Matches wird geblättert. Live per Socket, optional
mit STREAM_KEY geschützt, ohne Codes oder Verbindungsdaten.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
SPP UserandClaude Opus 5.5 committed 2026-10-25 19:32:53 +01:00
1 parent 54bfe198d8
commit 8996294d7e
11 files changed
+495 -3

No files matched your search

+29
View File
@@ -348,6 +348,35 @@ test('Nach Map-Ende lädt die nächste Map automatisch, entschiedene Serie wird
}
});
test('Stream-Übersicht aller Matches: Inhalte, keine Geheimnisse, optionaler Schlüssel', async () => {
const { app, call, close } = await setup({ streamKey: 'geheim123' });
try {
const lobby = (await call('POST', '/matches', { body: { teamA: 'Lobby A', teamB: 'Lobby B', mode: 'wingman', format: 'bo1' } })).body;
const { id, org, tokens } = await readyWingmanMatch(call, 'bo3');
await call('POST', `/matches/${id}/veto/start`, { token: org });
await call('POST', `/matches/${id}/veto/action`, { token: tokens.a1, body: { stepIndex: 0, map: 'de_inferno' } });
assert.equal((await call('GET', '/stream/overview')).status, 403);
assert.equal((await call('GET', '/stream/overview?key=falsch')).status, 403);
const res = await call('GET', '/stream/overview?key=geheim123');
assert.equal(res.status, 200);
const { active, upcoming } = res.body;
assert.equal(active.length, 1);
assert.equal(active[0].status, 'veto');
assert.equal(active[0].veto.maps.find((m) => m.id === 'de_inferno').status, 'banned');
assert.equal(active[0].veto.current.team, 'B');
assert.ok(upcoming.some((m) => m.id === lobby.id));
const json = JSON.stringify(res.body);
const row = app.service.getMatch(id);
for (const secret of [row.code_a, row.code_b, row.code_spectator, app.service.serverRow(id).rcon_password, app.service.serverRow(id).server_password]) {
assert.ok(!json.includes(secret), 'keine Codes oder Passwörter in der Stream-Übersicht');
}
} finally {
await close();
}
});
test('Spieler verlassen die Lobby, Captain geht über', async () => {
const { call, close } = await setup();
try {