diff --git a/server/pruef-haus-trennung.mjs b/server/pruef-haus-trennung.mjs index c4e6cb93..3d30df7a 100644 --- a/server/pruef-haus-trennung.mjs +++ b/server/pruef-haus-trennung.mjs @@ -347,14 +347,27 @@ console.log("=== Personen & Zugaenge ==="); ok(namen(a.crew).includes("Personen & Zugänge"), `die Kachel steht auf crew. (${namen(a.crew).length} Kacheln)`); - /* Und NICHT bei der rechten Hand: Die Seite haengt serverseitig an - nurAdmin, ein Knopf dorthin brachte ihr eine Absage. */ + /* UND BEI DER RECHTEN HAND EBENFALLS -- diese Erwartung hat sich + gedreht, und das gehoert hierhergeschrieben. + + Zuerst stand hier das Gegenteil: Die Kachel durfte bei ihr NICHT + stehen, weil die Seite serverseitig an `nurAdmin` hing und ein + Knopf, der eine Absage bringt, schlimmer ist als kein Knopf. Das + war richtig -- solange sie die Seite nicht durfte. + + Filipe danach: "ich will dass die rechte hand auch alle sieht." + Also darf sie sie, lesend. Damit stimmt der Knopf wieder. + + Die Pruefung ist deshalb nicht schwaecher geworden: Sie verlangt + weiterhin, dass Kachel und Zugang DASSELBE sagen -- nur sagen sie + jetzt beide ja statt beide nein. Der Fall, den sie verhindert, ist + unveraendert: ein Knopf ohne Raum dahinter. */ const h = await hole("/workspace/api/ich", { host: CREW, keks: hand.keks }); - ok(!(h.daten?.bereiche || []).map((k) => k.name).includes("Personen & Zugänge"), - "und nicht bei der rechten Hand -- sie darf die Seite nicht"); + ok((h.daten?.bereiche || []).map((k) => k.name).includes("Personen & Zugänge"), + "die Kachel steht auch bei der rechten Hand"); const hZugriff = await hole("/workspace/api/verwaltung/personen", { host: CREW, keks: hand.keks }); - ok(hZugriff.status === 404, - `die Seite selbst weist sie ab (${hZugriff.status}) -- die Kachel haette sie belogen`); + ok(hZugriff.status === 200, + `und die Seite laesst sie herein (${hZugriff.status}) -- Kachel und Zugang sagen dasselbe`); const liste = await beide("/workspace/api/verwaltung/personen", dogi.keks); const wer = (x) => (x?.personen || []).map((p) => p.name); @@ -471,7 +484,74 @@ console.log("=== Die Rolle aendern ==="); } /* ======================================================================= - 11. Die Gegenprobe zur Regel selbst + 11. ALLE KATEGORIEN -- und niemand faellt lautlos weg + ======================================================================= + + Filipe, mit Bildschirmfoto der Personenseite: "ich muss alle + kategorien da sehen. und ich will dass die rechte hand auch alle + sieht." + + Auf dem Bild stand genau EIN Abschnitt: DogFather. VanVan war in + derselben Minute zur rechten Hand geworden -- und damit aus der + Liste verschwunden. Nicht aus der Antwort des Servers: Der schickte + sie mit. Der Browser gruppierte nach einer Liste mit fuenf Rollen, + und wer dort nicht steht, wurde nicht gezeichnet. + + DIESE PRUEFUNG VERGLEICHT DESHALB BEIDE SEITEN: was der Server + liefert, und was am Ende auf dem Bildschirm steht. Eine Pruefung, die + nur die Antwort ansieht, waere hier gruen gewesen. + ======================================================================= */ +console.log(""); +console.log("=== Alle Kategorien ==="); +{ + const liste = (await hole("/workspace/api/verwaltung/personen", + { host: CREW, keks: dogi.keks })).daten; + const rollen = new Set((liste?.personen || []).map((p) => p.rolle)); + ok(rollen.has("admin") && rollen.has("hand"), + `der Server liefert mehrere Rollen (${[...rollen].join(", ")})`); + + /* Die Ueberschriften fuer die Rollen, die im Browser nicht stehen + duerfen, kommen mit der Antwort. Ohne sie faellt die Oberflaeche + auf den Rollennamen zurueck -- lesbar, aber roh. */ + const zusatz = (liste?.zusatzrollen || []).map((r) => r.wert); + ok(zusatz.includes("hand") && zusatz.includes("modi"), + `und die Ueberschriften dazu (${zusatz.join(", ") || "keine"})`); + + /* Und dieselbe Auskunft an die rechte Hand -- sonst saehe sie + dieselbe leere Seite wie DogFather vorhin. */ + const beiHand = (await hole("/workspace/api/verwaltung/personen", + { host: CREW, keks: hand.keks })).daten; + ok(Array.isArray(beiHand?.personen) && beiHand.personen.length > 0, + `die rechte Hand bekommt die Liste (${beiHand?.personen?.length || 0} Menschen)`); + ok((beiHand?.zusatzrollen || []).length > 0, + "samt der Ueberschriften"); + + /* SIE LIEST NUR. Jeder schreibende Weg bleibt zu -- gemessen, nicht + angenommen, denn genau hier waere aus "sehen" versehentlich + "verwalten" geworden. */ + const codeVersuch = await hole(`/workspace/api/verwaltung/personen/${idModi}/code`, + { host: CREW, methode: "POST", keks: hand.keks, rumpf: "{}" }); + ok(codeVersuch.status === 404, `sie kann keinen Code neu setzen (${codeVersuch.status})`); + const rolleVersuch = await hole(`/workspace/api/verwaltung/personen/${idModi}/rolle`, + { host: CREW, methode: "PUT", keks: hand.keks, rumpf: JSON.stringify({ rolle: "modi" }) }); + ok(rolleVersuch.status === 404, `und keine Rolle vergeben (${rolleVersuch.status})`); + const anlegen = await hole("/workspace/api/verwaltung/personen", + { host: CREW, methode: "POST", keks: hand.keks, + rumpf: JSON.stringify({ name: "Nochwer", rolle: "modi" }) }); + ok(anlegen.status === 404, `und niemanden anlegen (${anlegen.status})`); + + /* GEGENPROBE: DogFather darf all das sehr wohl -- sonst hiessen die + drei 404 oben auch dann gruen, wenn die Wege ueberhaupt kaputt + waeren. Der Rollenwechsel weiter oben hat das schon gezeigt; hier + genuegt das Anlegen. */ + const dogiLegtAn = await hole("/workspace/api/verwaltung/personen", + { host: CREW, methode: "POST", keks: dogi.keks, + rumpf: JSON.stringify({ name: "Neues Teammitglied", rolle: "modi" }) }); + ok(dogiLegtAn.status === 201, `DogFather kann es (${dogiLegtAn.status})`); +} + +/* ======================================================================= + 12. Die Gegenprobe zur Regel selbst ======================================================================= */ console.log(""); console.log("=== Haengt es wirklich an der Adresse? ==="); diff --git a/server/pruef-personen-formular.mjs b/server/pruef-personen-formular.mjs index 11909e61..bf4201f0 100644 --- a/server/pruef-personen-formular.mjs +++ b/server/pruef-personen-formular.mjs @@ -63,6 +63,19 @@ function anlegen(name, rolle, code) { anlegen("Dogfather", "admin", "CODE-DOGI-0001"); anlegen("Cigdem", "manager", "CODE-CIGDEM-01"); anlegen("Tili", "creator", "CODE-TILI-0001"); +/* ZWEI MENSCHEN MIT ROLLEN, DIE DER BROWSER NICHT KENNT (10.09.2026). + + assets/js/personen.js gruppiert nach einer Liste mit fuenf Rollen, + und die Namen der beiden hier duerfen dort nicht stehen -- sie + gehoeren in keine Datei, die jeder herunterlaedt. Bis heute fiel + damit jeder heraus, der eine davon hat: kein Fehler, keine Luecke, + kein Hinweis. + + Aufgefallen ist es, als VanVan die rechte Hand wurde und in derselben + Minute aus der Personenliste verschwand. Filipe hat das + Bildschirmfoto geschickt: ein einziger Abschnitt, "DogFather". */ +anlegen("VanVan", "hand", "CODE-HAND-0001"); +anlegen("Ayla", "modi", "CODE-TEAM-0001"); d.close(); const { chromium } = await import( @@ -305,6 +318,72 @@ ok(await api(cigdem, "/workspace/api/aufgaben") === 200, "die Managerin arbeitet ansonsten unverändert weiter (Aufgaben)"); ok(await api(cigdem, "/workspace/api/calls") === 200, " und die Gespräche auch"); +/* ===================================================================== + NIEMAND FAELLT LAUTLOS WEG (10.09.2026) + + Die eigentliche Pruefung dieser Datei zum Thema Rollen: Was der + Server liefert, MUSS auf dem Bildschirm stehen. Eine Pruefung, die + nur die Antwort des Servers ansieht, waere hier gruen gewesen -- er + hat VanVan die ganze Zeit mitgeschickt. + + VERGLICHEN WIRD DESHALB ZAHL GEGEN ZAHL: wie viele Menschen kamen + an, wie viele stehen da. Nicht "steht VanVan da" -- das waere ein + Name, den man beim naechsten Umbau anpasst, bis die Pruefung wieder + passt. Die Zahl kann man nicht zurechtbiegen. + ===================================================================== */ +console.log(""); +console.log("=== Steht jeder auf der Seite, den der Server schickt? ==="); +{ + await dogi.goto(BASIS + "/workspace/personen.html", { waitUntil: "networkidle" }); + await dogi.waitForTimeout(900); + const m = await dogi.evaluate(async () => { + const a = await fetch("/workspace/api/verwaltung/personen", { credentials: "same-origin" }); + const daten = await a.json(); + return { + vomServer: (daten.personen || []).length, + rollenVomServer: [...new Set((daten.personen || []).map((p) => p.rolle))].sort(), + aufDerSeite: document.querySelectorAll(".person, .person-karte, [class*='person__']").length + ? document.querySelectorAll("#liste .gruppe").length : -1, + /* AUFGEKLAPPT MESSEN. Die Abschnitte stehen zugeklappt da, und + zugeklappt sind ihre Zeilen gar nicht im Dokument -- eine Suche + im Text findet dann nichts, obwohl alles richtig ist. Beim + ersten Lauf meldete diese Zeile vier Fehler, die es nicht gab. + Also erst oeffnen, dann lesen. */ + namenAufDerSeite: (() => { + for (const k of document.querySelectorAll("#liste .gruppe__kopf")) k.click(); + return document.querySelector("#liste")?.textContent || ""; + })(), + zeilen: (() => { + for (const k of document.querySelectorAll("#liste .gruppe__kopf")) { + if (k.getAttribute("aria-expanded") !== "true") k.click(); + } + return document.querySelectorAll("#liste .person").length; + })(), + abschnitte: [...document.querySelectorAll("#liste .gruppe")] + .map((g) => g.dataset.rolle), + }; + }); + console.log(` Server: ${m.vomServer} Menschen in ${m.rollenVomServer.length} Rollen ` + + `(${m.rollenVomServer.join(", ")})`); + console.log(` Seite: ${m.abschnitte.length} Abschnitte (${m.abschnitte.join(", ")})`); + + ok(m.vomServer >= 5, `der Server liefert ${m.vomServer} Menschen`); + ok(m.zeilen === m.vomServer, + `und ebenso viele Zeilen stehen auf der Seite (${m.zeilen} von ${m.vomServer})`); + ok(m.abschnitte.length === m.rollenVomServer.length, + `fuer jede gelieferte Rolle steht ein Abschnitt da ` + + `(${m.abschnitte.length} von ${m.rollenVomServer.length})`); + for (const name of ["VanVan", "Ayla", "Tili", "Cigdem"]) { + ok(m.namenAufDerSeite.includes(name), `${name} steht auf der Seite`); + } + + /* GEGENPROBE: Findet die Messung ueberhaupt jemanden NICHT? Ein + erfundener Name darf nicht dastehen -- sonst prueft "steht auf der + Seite" gar nichts. */ + ok(!m.namenAufDerSeite.includes("Gibtsnichtsson"), + "und ein erfundener Name steht nicht da"); +} + const ERWARTET = 17; console.log(""); ok(geprueft >= ERWARTET, `es sind ${geprueft} Prüfungen gelaufen (erwartet mindestens ${ERWARTET})`); diff --git a/server/workspace-personen.js b/server/workspace-personen.js index 2e5f88f1..a88250ef 100644 --- a/server/workspace-personen.js +++ b/server/workspace-personen.js @@ -15,7 +15,7 @@ import express from "express"; import { - db, protokolliere, echteIp, sitzungLesen, personAnlegen, codeNeu, sitzungToken, personSperren, betreuungSetzen, scoutZuteilungSetzen, istLeitung, istDogFather, siehtAlles, ROLLEN_SORTIERUNG, ROLLEN_REIHE, istSpicy, verborgeneIds, TEAM_DOGI_ROLLEN, darfAnlegen, hausBedingung, + db, protokolliere, echteIp, sitzungLesen, personAnlegen, codeNeu, sitzungToken, personSperren, betreuungSetzen, scoutZuteilungSetzen, istLeitung, istDogFather, siehtModis, siehtAlles, ROLLEN_SORTIERUNG, ROLLEN_REIHE, istSpicy, verborgeneIds, TEAM_DOGI_ROLLEN, darfAnlegen, hausBedingung, } from "./workspace.js"; import { sicherungJetzt } from "./workspace-sicherung.js"; @@ -77,6 +77,29 @@ function nurAdmin(req, res, next) { return next(); } + /* DIE RECHTE HAND LIEST MIT (10.09.2026). + + Filipe: "ich muss alle kategorien da sehen. und ich will dass die + rechte hand auch alle sieht." + + LESEN, NICHT VERWALTEN -- und das ist keine Vorsicht von mir, + sondern sein eigenes Wort: "sieht". Codes, Sperren, Loeschen, + Rollen vergeben und das Protokoll bleiben bei DogFather; "Nur + DogFather hat alle endgueltigen Rechte" gilt unveraendert. + + DIESELBE BAUWEISE WIE BEI SPICY MEDIA darueber: eine Methode, eine + Adresse, eine Rolle. Wer hier etwas anderes einbaut, hat zwei + Fassungen derselben Ausnahme -- und die zweite ist die, die + irgendwann mehr durchlaesst als gedacht. + + WELCHE Menschen sie zu sehen bekommt, entscheidet sie nicht: Auf + ihrer Adresse grenzt `hausBedingung` die Liste ohnehin auf Team + Dogi ein. */ + if (person.rolle === "hand" && nurListe) { + req.person = person; + return next(); + } + if (!istDogFather(person)) return res.status(404).json({ fehler: "nicht_gefunden" }); req.person = person; next(); @@ -232,7 +255,17 @@ personenRouter.get("/workspace/api/verwaltung/personen", (req, res) => { Browser. `schutz` ist das vorhandene Schild-Zeichen -- es passt zur Moderation und spart ein neues, das in der Zeichenliste wieder fuer alle sichtbar waere. */ - zusatzrollen: istDogFather(req.person) + /* SIE GEHEN AN ALLE, DIE DIE LISTE UEBERHAUPT BEKOMMEN -- also + an DogFather und an die rechte Hand, nicht an Spicy Media oder + einen Manager. + + Sie sind nicht nur die Auswahl beim Anlegen, sondern seit + heute auch die UEBERSCHRIFTEN der Abschnitte: Der Browser + kennt nur die fuenf Rollen aus bereiche.js, und wer dort nicht + steht, wurde bis eben nicht gezeichnet. VanVan verschwand + genau in dem Moment aus der Liste, in dem sie die rechte Hand + wurde -- ohne Fehler, ohne Luecke, ohne Hinweis. */ + zusatzrollen: siehtModis(req.person) ? [{ wert: "modi", name: "Modi", /* DIE PFOTE (Filipe, 10.09.2026 mit Bildschirmfoto: "bei diff --git a/server/workspace.js b/server/workspace.js index fc21b8bb..01128523 100644 --- a/server/workspace.js +++ b/server/workspace.js @@ -572,7 +572,17 @@ const PERSONEN_KACHEL = { hinzufuegt, bekommt sie hier automatisch mit. Eine zweite Liste waere die Stelle, an der die rechte Hand irgendwann weniger sieht als das Team, das sie koordinieren soll. */ -const HAND_BEREICHE = [...MODI_BEREICHE, EINGANG_KACHEL]; +/* PERSONEN & ZUGAENGE GEHOERT DAZU (10.09.2026, zweite Fassung). + + Erst stand die Kachel nur bei DogFather -- die Seite haengt am + Server an `nurAdmin`, und ein Knopf, der eine Absage bringt, ist + schlimmer als kein Knopf. + + Filipe danach: "ich will dass die rechte hand auch alle sieht." + Also bekommt sie die Seite -- lesend. Damit stimmt der Knopf wieder, + und er steht in derselben Liste wie alles andere, was sie und + DogFather auf dieser Adresse teilen. */ +const HAND_BEREICHE = [...MODI_BEREICHE, EINGANG_KACHEL, PERSONEN_KACHEL]; export function bereicheFuer(person) { if (person?.rolle === "modi") return MODI_BEREICHE; @@ -591,17 +601,11 @@ export function bereicheFuer(person) { ihn waere die, die beim naechsten Umbau auseinanderlaeuft -- und sie stuende ausserdem gegen die Hausregel, ihn nicht ueber sein Team zu stellen. */ - /* AUF DER TEAM-ADRESSE: die Kacheln des Teams, plus die Verwaltung. - - WARUM DIE VERWALTUNG NUR HIER UND NICHT IN HAND_BEREICHE: Die - Personenseite haengt serverseitig an `nurAdmin`. Stuende die Kachel - in der Liste der rechten Hand, fuehrte sie bei ihr auf eine 404 -- - ein Knopf, der eine Absage bringt, ist schlimmer als kein Knopf. - Wenn sie das duerfen soll, ist das eine eigene Entscheidung und - gehoert an dieselbe Stelle wie nurAdmin, nicht hierher. */ - if (person?.haus === "crew") { - return istDogFather(person) ? [...HAND_BEREICHE, PERSONEN_KACHEL] : HAND_BEREICHE; - } + /* Auf der Team-Adresse sehen DogFather und die rechte Hand dieselben + Kacheln. Eine eigene Liste fuer ihn waere die, die beim naechsten + Umbau auseinanderlaeuft -- und sie stuende gegen die Hausregel, + ihn nicht ueber sein Team zu stellen. */ + if (person?.haus === "crew") return HAND_BEREICHE; return null; } @@ -3098,7 +3102,21 @@ const GESCHUETZT = { Eine Seite ist kein Schutz, sie ist ein Weg. Der Schutz steht in den Schnittstellen, und der ist unveraendert. */ - "/workspace/personen.html": ["spicy", "admin", "manager"], + /* 'hand' kam am 10.09.2026 dazu. Filipe: "ich will dass die rechte + Hand auch alle sieht." + + ES WAR DIE DRITTE SCHICHT, DIE ZUSTIMMEN MUSSTE. Die Kachel stand + da, die Schnittstelle liess sie lesen -- und die Seite selbst warf + sie auf die Startseite zurueck. Gefunden hat das nicht das Auge, + sondern pruef-rollen: Sie geht jede Kachel jeder Rolle ab und + schaut, wo man landet ("Rechte Hand Kachel personen.html LANDET + AUF start.html"). + + Dass die Seite aufgeht, gibt ihr nichts, was die Schnittstellen ihr + nicht ohnehin geben: Alles unter /workspace/api/verwaltung ausser + der Liste antwortet ihr weiterhin mit 404. Eine Seite ist kein + Schutz, sie ist ein Weg. */ + "/workspace/personen.html": ["spicy", "admin", "manager", "hand"], "/workspace/profil.html": ["spicy", "admin", "manager", "scout", "creator"], /* Der eigene Steckbrief -- jede Rolle hat einen. Ein Creator wird dort nicht hingeschickt (er sieht seinen auf profil.html), darf die diff --git a/workspace/app.webmanifest b/workspace/app.webmanifest index 423cec16..cf7c18ff 100644 --- a/workspace/app.webmanifest +++ b/workspace/app.webmanifest @@ -13,25 +13,25 @@ "theme_color": "#06090f", "icons": [ { - "src": "/assets/img/app-symbole/workspace-192.png?v=202609102339", + "src": "/assets/img/app-symbole/workspace-192.png?v=202609110010", "sizes": "192x192", "type": "image/png", "purpose": "any" }, { - "src": "/assets/img/app-symbole/workspace-512.png?v=202609102339", + "src": "/assets/img/app-symbole/workspace-512.png?v=202609110010", "sizes": "512x512", "type": "image/png", "purpose": "any" }, { - "src": "/assets/img/app-symbole/workspace-192-maskable.png?v=202609102339", + "src": "/assets/img/app-symbole/workspace-192-maskable.png?v=202609110010", "sizes": "192x192", "type": "image/png", "purpose": "maskable" }, { - "src": "/assets/img/app-symbole/workspace-512-maskable.png?v=202609102339", + "src": "/assets/img/app-symbole/workspace-512-maskable.png?v=202609110010", "sizes": "512x512", "type": "image/png", "purpose": "maskable" diff --git a/workspace/assets/js/personen.js b/workspace/assets/js/personen.js index 1341718c..5df8beee 100644 --- a/workspace/assets/js/personen.js +++ b/workspace/assets/js/personen.js @@ -143,6 +143,11 @@ } } + /* Die Rollen, die der Server mitschickt -- Auswahl beim Anlegen UND + Überschrift in der Liste. Eine Quelle für beides; zwei wären zwei + Gelegenheiten, dass eine nachgezogen wird und die andere nicht. */ + let zusatzAbschnitte = []; + const gewaehlteRolle = () => document.querySelector('.rollenwahl__knopf[data-an="ja"]')?.dataset.rolle || 'creator'; let ich = null; @@ -485,6 +490,11 @@ } const knoepfe = el('div', 'person__knoepfe'); + /* WER NUR LIEST, BEKOMMT KEINE KNOEPFE. Der Server antwortet ihr + auf jeden davon mit 404 -- ein Knopf, der eine Absage bringt, ist + schlimmer als kein Knopf. */ + if (ich.rolle === 'hand') { k.append(links, knoepfe); return k; } + knoepfe.append(tuKnopf('Neuer Code', async () => { const eigen = p.id === ich.id; const frage = eigen @@ -725,7 +735,37 @@ `filter((a) => a.drin.length)` erledigt den Rest von selbst: Ist niemand darin, gibt es den Abschnitt auch nicht. */ - const vorhanden = ROLLEN_ABSCHNITTE + /* ABSCHNITTE, DIE DER SERVER MITBRINGT (10.09.2026). + + Die Liste oben kennt fünf Rollen. Wer eine sechste hat, wurde bis + eben NICHT GEZEICHNET -- kein Fehler, keine Lücke, kein Hinweis. + VanVan verschwand genau in dem Moment aus der Personenliste, in + dem sie die rechte Hand wurde; Filipe hat es im Bildschirmfoto + geschickt ("ich muss alle kategorien da sehen"). + + Die Überschriften stehen NICHT hier. Diese Datei bekommt jeder, + der die Seite öffnet, und die Namen der verborgenen Rollen + gehören dort nicht hinein -- sie kommen mit der Liste vom + Server, an die, die sie sehen dürfen. Dieselbe Lösung wie bei der + Personenauswahl im Chat. + + DAS AUFFANGBECKEN DARUNTER ist der eigentliche Fortschritt: Käme + morgen eine siebte Rolle und niemand dächte an diese Stelle, + stünden ihre Leute trotzdem auf der Seite -- unter ihrem + Rollennamen, sichtbar, statt lautlos zu fehlen. Ein Abschnitt mit + einer unschönen Überschrift ist tausendmal besser als ein Mensch, + den es auf dem Bildschirm nicht gibt. */ + const abschnitte = [...ROLLEN_ABSCHNITTE]; + for (const r of zusatzAbschnitte) { + if (!r || !r.wert || abschnitte.some((a) => a.rolle === r.wert)) continue; + abschnitte.push({ rolle: r.wert, name: r.name || r.wert, unter: r.text || '' }); + } + for (const p of alle) { + if (abschnitte.some((a) => a.rolle === p.rolle)) continue; + abschnitte.push({ rolle: p.rolle, name: p.rolle, unter: '' }); + } + + const vorhanden = abschnitte .map((a) => ({ ...a, drin: alle.filter((p) => p.rolle === a.rolle) })) .filter((a) => a.drin.length); @@ -878,6 +918,7 @@ if (!a.ok) { melde('Personen konnten nicht geladen werden.'); return; } const { personen, betreuer, zusatzrollen } = await a.json(); betreuerListe = betreuer || []; + zusatzAbschnitte = Array.isArray(zusatzrollen) ? zusatzrollen : []; rollenwahlErgaenzen(zusatzrollen); alle = personen; ziel.textContent = ''; @@ -995,7 +1036,22 @@ if (!a.ok) { location.assign('/workspace/'); return; } ich = await a.json(); } catch { return; } - if (!LEITUNG.has(ich.rolle)) { location.assign('/workspace/start.html'); return; } + /* DIE RECHTE HAND KOMMT HEREIN, ABER NUR ZUM LESEN (10.09.2026). + + Filipe: "ich will dass die rechte hand auch alle sieht." + + `LEITUNG` aus bereiche.js kennt sie nicht und darf sie nicht + kennen -- die Rolle steht in keiner ausgelieferten Datei. Sie + wird deshalb hier daneben zugelassen, nicht dort hineingesetzt. + + DAS IST KEINE SICHERUNG, sondern eine Weiche: Was sie darf, + entscheidet der Server (nurAdmin lässt sie nur an die Liste, und + nur lesend). Diese Zeile erspart ihr nur den Umweg über eine + Seite, die sie sofort wieder wegschickt. */ + const nurLesen = ich.rolle === 'hand'; + if (!LEITUNG.has(ich.rolle) && !nurLesen) { + location.assign('/workspace/start.html'); return; + } window.werZeigen?.(ich); /* =================================================================== @@ -1019,6 +1075,32 @@ Verwaltungsschnittstelle ab, und die ist zu. Eine Abfrage, von der man weiss, dass sie 404 gibt, sollte man nicht stellen -- sie fuellt nur das Serverlog. */ + /* DRITTE AUSBAUSTUFE: NUR LESEN. + + Sie steht VOR `nurAnlegen`, weil sie enger ist -- wer nur liest, + legt auch nichts an. Stünde sie danach, bekäme die rechte Hand + zuerst das Anlegeformular und danach den Hinweis, dass sie nichts + darf; sichtbar wäre beides. */ + if (nurLesen) { + document.body.dataset.nurLesen = 'ja'; + /* SIE LEGT NIEMANDEN AN. Das Ausblenden ist keine Sicherung -- + der Server antwortet ihr mit 404 --, es erspart ihr nur ein + Formular, dessen Absenden eine Absage bringt. Beide Elemente, + nicht nur eines: Der Knopf oeffnet das Formular, und ein + verstecktes Formular mit sichtbarem Knopf ist eine Tuer ohne + Raum dahinter. */ + const auf = $('neu-oeffnen'); if (auf) auf.hidden = true; + const form = $('neu'); if (form) form.hidden = true; + const zeile = $('unterzeile'); + if (zeile) { + zeile.textContent = 'Du siehst hier das ganze Team. Codes, Sperren, ' + + 'Rollen und das Protokoll bleiben bei DogFather.'; + zeile.hidden = false; + } + await laden(); + return; + } + const nurAnlegen = ich.rolle !== 'admin'; if (nurAnlegen) { document.body.dataset.nurAnlegen = 'ja'; diff --git a/workspace/aufgaben.html b/workspace/aufgaben.html index 3073ed22..0d168304 100644 --- a/workspace/aufgaben.html +++ b/workspace/aufgaben.html @@ -12,19 +12,19 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - + + + + + + - +
@@ -252,10 +252,10 @@ - - - - - + + + + +