From 85101176d2b8d438aafaca4ddd5c100b69b44380 Mon Sep 17 00:00:00 2001 From: Dogfather Date: Mon, 28 Sep 2026 02:01:32 +0200 Subject: [PATCH] Zwei fuehren die Sendung: DogFather und die rechte Hand MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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." DREI DINGE AENDERN SICH, UND ZWAR GENAU DIESE DREI 1. VORBEREITEN UND EINSCHALTEN duerfen jetzt beide -- einstellen, Vorbereitung, auf Sendung, beenden, Gaeste holen und entfernen, stummschalten, Anordnung, Video steuern. Beide dasselbe; es gibt hier keinen Ersten und keinen Zweiten. Das ist eine AUFGABE und kein Rang: Wer die Sendung fuehrt, bedient die Technik. 2. „ALLES SEHEN" heisst die Namensliste derer, die zusehen. Die bekamen bisher auch die linke Hand und die Modis, weil sie moderieren duerfen. Das war eine Vermischung zweier Dinge, die nichts miteinander zu tun haben: Wer einen Beitrag wegnehmen darf, muss deshalb nicht wissen, wer im Saal sitzt. Ab jetzt bekommt die Liste nur, wer auf der Buehne steht. Die Moderation bleibt unveraendert bei DogFather, beiden Haenden und den Modis -- einen Beitrag wegzunehmen ist weder „alles sehen" noch „vorbereiten" noch „einschalten", sondern dasselbe, was sie im Treff ohnehin tun. 3. WER AUF SENDUNG DRUECKT, IST IM BILD. Vorher stand als Host, wer zuletzt etwas eingestellt hatte. Mit zwei Leuten, die vorbereiten duerfen, waere das eine Falle: VanVan richtet am Nachmittag alles ein, Filipe drueckt abends auf Sendung -- und im Bild stuende VanVans Name, waehrend Filipe redet. Beim Einstellen wird `host_id` deshalb nur noch gefuellt, wenn dort noch niemand steht (damit die Ankuendigung „Als Naechstes" jemanden nennen kann). Wer die Sendung FUEHRT, entscheidet sich beim Einschalten. GEPRUEFT IN BEIDE RICHTUNGEN Nur zu messen, wer darf, hiesse: Die Tuer laesst sich spaeter weit aufmachen, ohne dass etwas rot wird. pruef-reaktion misst deshalb auch, wer ausdruecklich NICHT darf -- und dass es genau zwei sind: genau zwei fuehren die Sendung: admin, hand die rechte Hand darf einstellen / vorbereiten / Anordnung linke, modi, gast: duerfen nicht einstellen (403) ein Modi holt niemanden dazu (403) wer eingeschaltet hat, fuehrt die Sendung (Filipe) drueckt die rechte Hand, fuehrt sie (VanVan) die rechte Hand sieht, WER dabei ist -- sie fuehrt mit linke, modi: moderieren, bekommen die Namensliste aber nicht admin/hand: sehen Regiepult -- linke/modi/gast: nicht 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. pruef-reaktion 74 -> 88 Punkte, 0 Fehler. Dazu gruen: meldungen 8, rechtetafel 19, verborgen 25, modi-verborgen 85. --- server/pruef-reaktion.mjs | 89 ++++++++++++++++++++++++++++++++- server/workspace-reaktion.js | 53 +++++++++++++++++--- workspace/anruf-probe.html | 10 ++-- workspace/app.webmanifest | 8 +-- workspace/assets/js/meldung.js | 3 +- workspace/aufgaben.html | 38 +++++++------- workspace/automation.html | 32 ++++++------ workspace/befinden.html | 34 ++++++------- workspace/bereich.html | 44 ++++++++-------- workspace/bewerben.html | 38 +++++++------- workspace/bewerbungen.html | 36 ++++++------- workspace/calls.html | 34 ++++++------- workspace/chat.html | 40 +++++++-------- workspace/content.html | 34 ++++++------- workspace/crew-index.html | 12 ++--- workspace/crew.webmanifest | 8 +-- workspace/dateien.html | 34 ++++++------- workspace/entwicklung.html | 36 ++++++------- workspace/hilfe.html | 30 +++++------ workspace/index.html | 10 ++-- workspace/kalender.html | 34 ++++++------- workspace/leistung.html | 32 ++++++------ workspace/material.html | 32 ++++++------ workspace/notizen.html | 28 +++++------ workspace/personen.html | 32 ++++++------ workspace/profil.html | 36 ++++++------- workspace/reaktion.html | 30 +++++------ workspace/rechte.html | 34 ++++++------- workspace/report.html | 36 ++++++------- workspace/scouting.html | 32 ++++++------ workspace/start.html | 32 ++++++------ workspace/startcheck.html | 34 ++++++------- workspace/steckbrief.html | 36 ++++++------- workspace/support.html | 28 +++++------ workspace/talente.html | 36 ++++++------- workspace/team.html | 32 ++++++------ workspace/teamlage.html | 34 ++++++------- workspace/teilen.html | 30 +++++------ workspace/treff-moderation.html | 32 ++++++------ workspace/treff-regeln.html | 32 ++++++------ workspace/uebersicht.html | 32 ++++++------ workspace/unsere-seiten.html | 30 +++++------ workspace/unterstuetzen.html | 32 ++++++------ workspace/werdegang.html | 32 ++++++------ workspace/willkommen.html | 30 +++++------ workspace/wissen.html | 34 ++++++------- 46 files changed, 796 insertions(+), 669 deletions(-) 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`. --> - - + + - +