diff --git a/server/pruef-reaktion.mjs b/server/pruef-reaktion.mjs index f04d8ddd..5a12fd43 100644 --- a/server/pruef-reaktion.mjs +++ b/server/pruef-reaktion.mjs @@ -174,18 +174,59 @@ melde("=== 2. Die Agentur kennt sie nicht ==="); melde(""); melde("=== 3. Wer die Sendung fuehrt ==="); { - for (const rolle of ["hand", "linke", "modi", "gast"]) { + /* ZWEI FUEHREN, UND NUR DIE ZWEI (Filipe, 28.09.2026): + „die rolle dogfather und vanvan sollen alles sehen und bereit + machen auch vorher. nur die zwei sollen alles sehen, vorbereiten + und einschakten koennen." + + Geprueft wird deshalb in BEIDE Richtungen -- wer darf, und wer + ausdruecklich nicht. Nur die eine Haelfte zu messen hiesse: Die + Tuer laesst sich spaeter weit aufmachen, ohne dass etwas rot + wird. */ + const { REAKTION_HOST_ROLLEN } = await import("./workspace-reaktion.js"); + ok(REAKTION_HOST_ROLLEN.has("admin") && REAKTION_HOST_ROLLEN.has("hand") + && REAKTION_HOST_ROLLEN.size === 2, + `genau zwei fuehren die Sendung: ${[...REAKTION_HOST_ROLLEN].join(", ")}`); + + for (const rolle of ["linke", "modi", "gast"]) { const a = await roh(CREW, "/workspace/api/reaktion", { method: "PUT", keks: k[rolle], rumpf: { titel: "Nicht du" }, }); ok(a.code === 403, `${rolle}: darf nicht einstellen (${a.code})`); } + + /* Die rechte Hand darf ALLES, was zum Fuehren gehoert -- nicht nur + einstellen. Ein Knopf, der da ist und mit 403 antwortet, ist eine + Falle; deshalb wird jeder einzeln nachgefahren. */ + const wege = [ + ["einstellen", "PUT", "/workspace/api/reaktion", { titel: "VanVan richtet ein" }], + ["vorbereiten", "POST", "/workspace/api/reaktion/stand", { stand: "vorbereitung" }], + ["Anordnung", "POST", "/workspace/api/reaktion/layout", { layout: "gleich" }], + ]; + for (const [was, art, pfad, rumpf] of wege) { + const a = await roh(CREW, pfad, { method: art, keks: k.hand, rumpf }); + ok(a.code === 200, `die rechte Hand darf ${was} (${a.code})`); + } + await roh(CREW, "/workspace/api/reaktion/stand", { method: "POST", keks: k.hand, rumpf: { stand: "zu" } }); + await roh(CREW, "/workspace/api/reaktion/layout", { method: "POST", keks: k.admin, rumpf: { layout: "kino" } }); + const a = await roh(CREW, "/workspace/api/reaktion", { method: "PUT", keks: k.admin, rumpf: { titel: "Wir schauen den Trailer", video: "https://www.youtube.com/watch?v=dQw4w9WgXcQ" }, }); ok(a.code === 200 && a.j?.video === "dQw4w9WgXcQ", - `DogFather schon -- und aus der Adresse wird die Kennung (${a.j?.video})`); + `DogFather auch -- und aus der Adresse wird die Kennung (${a.j?.video})`); + + /* DAS REGIEPULT HAENGT AN `ich.host` UND AN NICHTS SONST. Ein + zweiter Ort, an dem der Browser dieselbe Frage noch einmal + beantwortet, waere der, der spaeter abweicht -- und dann stuenden + Knoepfe da, die mit 403 antworten. */ + for (const [rolle, soll] of [["admin", true], ["hand", true], + ["linke", false], ["modi", false], ["gast", false]]) { + const b = await roh(CREW, "/workspace/api/reaktion", { keks: k[rolle] }); + ok(b.j?.ich?.host === soll, + `${rolle}: ${soll ? "sieht" : "sieht kein"} Regiepult (ich.host=${b.j?.ich?.host})`); + } } /* ---- Die Kennung kommt aus jeder Form, die man wirklich einfuegt ---- */ @@ -240,6 +281,32 @@ melde("=== 4. zu -> vorbereitung -> live -> zu ==="); }); ok(e.code === 200 && e.j?.stand === "live" && e.j?.gestartet_am, `auf Sendung -- mit Startzeit (${e.j?.stand})`); + + /* WER EINSCHALTET, IST IM BILD. + + Vorher stand als Host, wer zuletzt etwas eingestellt hatte. Mit + zwei Leuten, die vorbereiten duerfen, ist das eine Falle: VanVan + richtet nachmittags ein, Filipe drueckt abends auf Sendung -- und + im Bild stuende VanVans Name, waehrend Filipe redet. */ + ok(e.j?.host?.id === IDS.admin, + `wer eingeschaltet hat, fuehrt die Sendung (${e.j?.host?.name})`); + + await roh(CREW, "/workspace/api/reaktion/stand", { method: "POST", keks: k.admin, rumpf: { stand: "zu" } }); + await roh(CREW, "/workspace/api/reaktion", { + method: "PUT", keks: k.admin, rumpf: { titel: "Wir schauen den Trailer", video: "dQw4w9WgXcQ" }, + }); + const f = await roh(CREW, "/workspace/api/reaktion/stand", { + method: "POST", keks: k.hand, rumpf: { stand: "live" }, + }); + ok(f.j?.host?.id === IDS.hand, + `drueckt die rechte Hand, fuehrt sie (${f.j?.host?.name})`); + /* Und zurueck auf DogFather, damit der Rest der Pruefung von ihm + aus weiterlaeuft. */ + await roh(CREW, "/workspace/api/reaktion/stand", { method: "POST", keks: k.hand, rumpf: { stand: "zu" } }); + await roh(CREW, "/workspace/api/reaktion", { + method: "PUT", keks: k.admin, rumpf: { titel: "Wir schauen den Trailer", video: "dQw4w9WgXcQ" }, + }); + await roh(CREW, "/workspace/api/reaktion/stand", { method: "POST", keks: k.admin, rumpf: { stand: "live" } }); } /* ---- Ohne Video kein Live ---- */ @@ -274,11 +341,25 @@ melde("=== 5. Dabei sein ==="); ok(Array.isArray(a.j?.zuschauer) && a.j.zuschauer.length === 3, "DogFather sieht, WER dabei ist"); + const h = await roh(CREW, "/workspace/api/reaktion", { keks: k.hand }); + ok(Array.isArray(h.j?.zuschauer) && h.j.zuschauer.length === 3, + "die rechte Hand sieht es auch -- sie fuehrt mit"); + const z = await roh(CREW, "/workspace/api/reaktion", { keks: k.gast }); ok(z.j?.zuschauer === null, "ein Zuschauer bekommt die Namensliste NICHT"); ok(z.j?.dabei === 3, `die Zahl sieht er aber (${z.j?.dabei})`); + /* „NUR DIE ZWEI SOLLEN ALLES SEHEN." Die Moderation stand hier + frueher mit drin, weil sie Beitraege wegnehmen darf -- das ist + eine Vermischung zweier Dinge, die nichts miteinander zu tun + haben. Wegnehmen duerfen sie weiter (Abschnitt 7). */ + for (const rolle of ["linke", "modi"]) { + const m = await roh(CREW, "/workspace/api/reaktion", { keks: k[rolle] }); + ok(m.j?.zuschauer === null, + `${rolle}: moderiert, bekommt die Namensliste aber nicht`); + } + /* Jeder Dabeisitzende hat einen Kameraplatz bekommen -- es sind erst drei, und zwoelf waeren erlaubt. */ ok(a.j.zuschauer.every((x) => x.sicht === true), @@ -343,6 +424,10 @@ melde("=== 6. Ein bis zwei Gaeste ==="); method: "POST", keks: k.gast, rumpf: { person_id: IDS.modi }, }); ok(f.code === 403, `ein Gast holt niemanden dazu (${f.code})`); + const f2 = await roh(CREW, "/workspace/api/reaktion/gast", { + method: "POST", keks: k.modi, rumpf: { person_id: IDS.linke }, + }); + ok(f2.code === 403, `ein Modi auch nicht (${f2.code})`); const w = await roh(CREW, `/workspace/api/reaktion/gast/${IDS.gast2}`, { method: "DELETE", keks: k.admin, diff --git a/server/workspace-reaktion.js b/server/workspace-reaktion.js index 13352772..4fb429b8 100644 --- a/server/workspace-reaktion.js +++ b/server/workspace-reaktion.js @@ -52,9 +52,25 @@ import { export const reaktionRouter = express.Router(); -/** Wer die Sendung fuehrt. */ -const HOST_ROLLEN = new Set(["admin"]); -/** Wer Beitraege aus dem Chat nehmen darf. */ +/** Wer die Sendung fuehrt: DogFather und die rechte Hand. + * + * Filipe am 28.09.2026: „die rolle dogfather und vanvan sollen alles + * sehen und bereit machen auch vorher. nur die zwei sollen alles + * sehen, vorbereiten und einschakten koennen." + * + * Das ist eine AUFGABE und kein Rang -- wer die Sendung fuehrt, + * bedient die Technik. Beide duerfen dasselbe; es gibt hier keinen + * Ersten und keinen Zweiten. */ +const HOST_ROLLEN = new Set(["admin", "hand"]); + +/** Wer Beitraege aus dem Chat nehmen darf. + * + * BLEIBT GROESSER ALS HOST_ROLLEN, und das ist Absicht: Einen + * Beitrag wegzunehmen ist weder „alles sehen" noch „vorbereiten" + * noch „einschalten" -- es ist dasselbe, was die Modis im Treff + * ohnehin tun. Wer moderiert, bekommt deshalb aber AUCH NICHT die + * Liste derer, die zusehen; die beiden Dinge hingen vorher + * zusammen, ohne dass es einen Grund dafuer gab. */ const MODERIERT = new Set(["admin", "hand", "linke", "modi"]); export const REAKTION_HOST_ROLLEN = HOST_ROLLEN; @@ -183,8 +199,15 @@ function lage(person) { nie an (sonst rufen zwei gleichzeitig an, und beide scheitern -- „glare"). Ohne die Liste kaeme das Bild eines Gastes deshalb bei keinem Zuschauer an. Zwei fuer sich richtige - Regeln, die zusammen ein Loch ergeben. */ - zuschauer: (istHost || binGast || MODERIERT.has(person.rolle)) + Regeln, die zusammen ein Loch ergeben. + + DIE MODERATION STAND HIER AUCH -- SEIT DEM 28.09. NICHT MEHR. + Filipe: „nur die zwei sollen alles sehen." Wer einen Beitrag + wegnehmen darf, muss deshalb nicht wissen, wer im Saal sitzt; + das war eine Vermischung zweier Dinge, die nichts miteinander + zu tun haben. Moderiert wird weiter -- im Chat sieht man + ohnehin, wer da ist. */ + zuschauer: (istHost || binGast) ? dabei.map((d) => ({ id: d.id, name: d.name, rolle: d.rolle, sicht: !!d.sicht })) : null, ich: { @@ -240,9 +263,23 @@ reaktionRouter.put("/workspace/api/reaktion", nurHost, express.json({ limit: "32 return res.status(400).json({ fehler: "beginn_vorbei" }); } + /* HOST_ID WIRD BEIM EINSTELLEN NUR GESETZT, WENN NOCH NIEMAND + DASTEHT (28.09.2026). + + Vorher stand hier, wer zuletzt etwas eingestellt hat. Mit + zwei Leuten, die vorbereiten duerfen, ist das eine Falle: + VanVan richtet am Nachmittag alles ein, Filipe drueckt + abends auf Sendung -- und im Bild stuende VanVans Name, + waehrend Filipe redet. + + Wer die Sendung FUEHRT, entscheidet sich beim Einschalten + (siehe /stand). Hier wird nur der leere Platz gefuellt, damit + die Ankuendigung „Als Naechstes" jemanden nennen kann. */ + const bisher = sendung(); db().prepare(`UPDATE reaktion SET titel = ?, video = ?, vorschau = ?, beginnt_am = ?, host_id = ?, geaendert = ? WHERE id = 1`) - .run(titel, video, vorschau, beginn, req.person.id, jetzt()); + .run(titel, video, vorschau, beginn, + bisher.host_id || req.person.id, jetzt()); const l = lage(req.person); melden("reaktion", { was: "eingestellt", lage: oeffentlich(l) }); @@ -272,6 +309,10 @@ reaktionRouter.post("/workspace/api/reaktion/stand", nurHost, express.json({ lim felder.gestartet_am = jetzt(); felder.laeuft = 1; felder.sekunde = 0; + /* WER EINSCHALTET, IST IM BILD. Seine Kamera bekommt den + Platz des Hosts -- und sein Name steht daran. Der andere + kann jederzeit als Gast dazukommen. */ + felder.host_id = req.person.id; } if (neu === "zu" && s.stand === "live") { /* WAS VORBEI IST, WANDERT IN DEN VERLAUF -- und der Live-Chat diff --git a/workspace/anruf-probe.html b/workspace/anruf-probe.html index c41fd152..66ea1b7e 100644 --- a/workspace/anruf-probe.html +++ b/workspace/anruf-probe.html @@ -16,8 +16,8 @@ verdeckt. Gefunden hat es pruef-struktur. Richtig sind `gate.css` (die Farbwerte des Hauses) und `haus.css`. --> - - + + - +