From 82335c783d417de22e43e5e616110163605cb9a8 Mon Sep 17 00:00:00 2001 From: Dogfather Date: Tue, 22 Sep 2026 01:39:12 +0200 Subject: [PATCH] Die rechte Hand legt selbst Personen an -- und sieht die Codes Filipe: "dan will ich dass die rechte hand auch neue personen hinzufuegen kann. also neue erstellen kann und die codes genau so sieht wie dogfather, damit sie das auch machen kann wenn er live ist." WAS SIE DARF: Modis und Community anlegen, und deren Codes neu setzen. Die Liste ist ABGELEITET aus ROLLEN_ZUM_AENDERN -- dieselben zwei Rollen, die sie ohnehin vergeben darf. Zwei Listen waeren zwei Gelegenheiten, eine davon zu aendern und die andere zu vergessen. WAS SIE NICHT DARF: eine zweite rechte Hand, eine linke Hand oder einen zweiten DogFather anlegen -- und an einer linken Hand auch nichts aendern. Ohne die zweite Schranke haette sie den Code einer linken Hand neu setzen koennen und damit einen Zugang in der Hand, der fast so viel darf wie sie selbst. Die alte Schranke kannte nur "admin" und "manager". NUR DIE RECHTE, NICHT DIE LINKE. `istHand()` haette beide getroffen; fuer die linke Hand ist "legt niemanden an" eine ausdrueckliche Entscheidung vom 21.09. VIER STELLEN IN DER OBERFLAECHE, die alle an Rollennamen hingen: `nurLesen = ich.rolle === 'hand'` -- sie bekam die Liste und kein Formular. Jetzt abgeleitet aus `darf_anlegen`. Die Wache darueber warf sie auf die Startseite, sobald `nurLesen` falsch wurde. Die Seite ging fuer sie einfach nicht auf, ohne Meldung. Der Sendeweg hing an `ich.rolle === 'admin'`. Fuer sie gab es damit GAR KEINEN: Die Seite antwortete "Fuer die Rolle modi gibt es hier keinen Weg" -- ein Satz, der wie ein Formularfehler klingt und eine fehlende Zeile war. UND EIN ECHTER FUND: `rollenwahlErgaenzen()` hing jede Zusatzrolle an das Formular, die mit der Personenliste kam -- ohne zu fragen, ob man sie anlegen darf. Solange nur DogFather das Formular sah, fiel es nicht auf: Er darf sie alle. Der rechten Hand bot es "rechte Hand" und "linke Hand" an. Der Server haette es abgelehnt -- aber der Knopf verriet eine Rolle, die sie nicht vergeben soll. Zwei Pruefungen waren dabei selbst kaputt: pruef-personen-formular erwartete sieben Rollen (seit "linke" am 21.09. sind es acht) und suchte den Namen im sichtbaren Text -- die Abschnitte sind zugeklappt und zeigen nur Anfangsbuchstaben. Beides abgeleitet statt gezaehlt. Geprueft: pruef-personen-formular 43/0 (war 34 ok / 2 FEHL), davon neun am echten Bildschirm auf der Crew-Adresse -- anmelden, Formular oeffnen, anlegen, Code lesen, Person in der Liste wiederfinden. pruef-haus-trennung 81/0 (war 72 ok / 2 FEHL), pruef-rollen-anlegen 11/0. --- server/pruef-haus-trennung.mjs | 64 +++++++++- server/pruef-personen-formular.mjs | 181 ++++++++++++++++++++++++++++- server/workspace-personen.js | 49 ++++++++ server/workspace.js | 18 +++ workspace/anruf-probe.html | 8 +- workspace/app.webmanifest | 8 +- workspace/assets/js/personen.js | 87 ++++++++++++-- workspace/aufgaben.html | 34 +++--- workspace/automation.html | 30 ++--- workspace/befinden.html | 28 ++--- workspace/bereich.html | 40 +++---- workspace/bewerben.html | 34 +++--- workspace/bewerbungen.html | 32 ++--- workspace/calls.html | 32 ++--- workspace/chat.html | 36 +++--- workspace/content.html | 32 ++--- workspace/crew-index.html | 10 +- workspace/crew.webmanifest | 8 +- workspace/dateien.html | 32 ++--- workspace/entwicklung.html | 28 ++--- workspace/hilfe.html | 26 ++--- workspace/index.html | 8 +- workspace/kalender.html | 32 ++--- workspace/leistung.html | 30 ++--- workspace/personen.html | 30 ++--- workspace/profil.html | 34 +++--- workspace/rechte.html | 28 ++--- workspace/report.html | 32 ++--- workspace/scouting.html | 30 ++--- workspace/start.html | 28 ++--- workspace/startcheck.html | 32 ++--- workspace/steckbrief.html | 34 +++--- workspace/talente.html | 30 ++--- workspace/team.html | 28 ++--- workspace/teamlage.html | 28 ++--- workspace/teilen.html | 26 ++--- workspace/treff-moderation.html | 28 ++--- workspace/treff-regeln.html | 28 ++--- workspace/uebersicht.html | 30 ++--- workspace/unsere-seiten.html | 24 ++-- workspace/werdegang.html | 28 ++--- workspace/willkommen.html | 22 ++-- workspace/wissen.html | 32 ++--- 43 files changed, 899 insertions(+), 540 deletions(-) diff --git a/server/pruef-haus-trennung.mjs b/server/pruef-haus-trennung.mjs index 14bffd05..9fb69f59 100644 --- a/server/pruef-haus-trennung.mjs +++ b/server/pruef-haus-trennung.mjs @@ -681,12 +681,50 @@ console.log("=== Alle Kategorien ==="); 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`, + /* SIE DARF AUCH CODES NEU SETZEN (22.09.2026). + ------------------------------------------------------------------ + Hier stand `=== 404` ("sie liest nur"). Filipe hat das umgedreht: + "die codes genau so sieht wie dogfather, damit sie das auch machen + kann wenn er live ist." + + Ein Code wird genau einmal angezeigt. Geht er verloren, ist der + Zugang ohne diesen Weg tot -- und dann muesste doch wieder + DogFather ran, also genau das, was nicht sein soll. */ + /* EIN FRISCHER MODI, KEIN GEBRAUCHTER (berichtigt 22.09.2026). + Hier stand `idModi` -- und der ist weiter oben laengst zur rechten + Hand befoerdert worden. Die Pruefung mass damit "darf sie an einer + rechten Hand etwas aendern" und nicht "darf sie an einem Modi". + Dieselbe Falle wie am 21.09. bei Ayla. */ + const frischFuerCode = await hole("/workspace/api/verwaltung/personen", + { host: CREW, methode: "POST", keks: dogi.keks, + rumpf: JSON.stringify({ name: "Codeprobe", rolle: "modi" }) }); + const idFuerCode = frischFuerCode.daten?.person?.id ?? frischFuerCode.daten?.id; + ok(!!idFuerCode, `ein frischer Modi zum Messen (${idFuerCode || "keiner"})`); + const codeVersuch = await hole(`/workspace/api/verwaltung/personen/${idFuerCode}/code`, { host: CREW, methode: "POST", keks: hand.keks, rumpf: "{}" }); - ok(codeVersuch.status === 404, `sie kann keinen Code neu setzen (${codeVersuch.status})`); + ok(codeVersuch.status === 200, + `sie kann einen Code neu setzen (${codeVersuch.status})`); + ok(typeof codeVersuch.daten?.code === "string" && codeVersuch.daten.code.length > 6, + `und sieht ihn dabei (${codeVersuch.daten?.code ? "ja" : "NEIN"})`); + + /* DIE GRENZE DAZU: an einer LINKEN HAND aendert sie nichts. Ohne + diese Schranke haette sie einen Zugang in der Hand, der fast so + viel darf wie sie selbst -- und aufgefallen waere es nicht, denn + die alte Schranke kannte nur "admin" und "manager". */ + { + const frisch = await hole("/workspace/api/verwaltung/personen", + { host: CREW, methode: "POST", keks: dogi.keks, + rumpf: JSON.stringify({ name: "Lino Zweit", rolle: "linke" }) }); + const idLinke = frisch.daten?.person?.id ?? frisch.daten?.id; + if (idLinke) { + const anLinke = await hole(`/workspace/api/verwaltung/personen/${idLinke}/code`, + { host: CREW, methode: "POST", keks: hand.keks, rumpf: "{}" }); + ok(anLinke.status === 403, + `an einer linken Hand aendert sie nichts (${anLinke.status})`); + } else { + ok(false, "die Gegenprobe konnte keine linke Hand anlegen -- nicht messbar"); + } + } /* ROLLEN WECHSELN DARF SIE SEIT DEM 20.09. -- aber nicht alles. Filipe: "ich will dass ich da auch die rollen der leute wechseln @@ -740,10 +778,24 @@ console.log("=== Alle Kategorien ==="); { host: CREW, methode: "PUT", keks: hand.keks, rumpf: JSON.stringify({ rolle: "hand" }) }); ok(zuHoch.status === 400, `eine zweite rechte Hand ernennt sie nicht (${zuHoch.status})`); + /* UND SIE LEGT PERSONEN AN (22.09.2026) -- Filipes ausdruecklicher + Wunsch. Hier stand `=== 404`. */ 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})`); + ok(anlegen.status === 201, `sie legt einen Modi an (${anlegen.status})`); + ok(typeof (anlegen.daten?.code) === "string", + `und bekommt den Code zu sehen (${anlegen.daten?.code ? "ja" : "NEIN"})`); + + /* ABER KEINE ZWEITE RECHTE HAND UND KEINE LINKE -- sonst waere + "sie darf anlegen" ein Weg, sich selbst hoehere Rechte zu bauen. */ + for (const rolle of ["hand", "linke", "admin"]) { + const zuHochAnlegen = await hole("/workspace/api/verwaltung/personen", + { host: CREW, methode: "POST", keks: hand.keks, + rumpf: JSON.stringify({ name: "Zu hoch " + rolle, rolle }) }); + ok(zuHochAnlegen.status >= 400, + `eine Rolle "${rolle}" legt sie nicht an (${zuHochAnlegen.status})`); + } /* GEGENPROBE: DogFather darf all das sehr wohl -- sonst hiessen die drei 404 oben auch dann gruen, wenn die Wege ueberhaupt kaputt diff --git a/server/pruef-personen-formular.mjs b/server/pruef-personen-formular.mjs index e3153ad5..cd931682 100644 --- a/server/pruef-personen-formular.mjs +++ b/server/pruef-personen-formular.mjs @@ -169,10 +169,25 @@ const mass = await dogi.evaluate(() => { DIE ZEILE WURDE GEDREHT, NICHT GELOESCHT: Dass `admin` FEHLT, ist jetzt eine eigene Aussage -- sonst haette die Liste unten still eine Rolle mehr bekommen koennen, ohne dass es jemand merkt. */ -ok(mass.karten === 7, `alle sieben vergebbaren Rollen stehen zur Wahl (${mass.karten})`); -ok(JSON.stringify([...mass.kartenRollen].sort()) - === JSON.stringify(["creator", "gast", "hand", "manager", "modi", "scout", "spicy"]), - `und es sind die richtigen (${mass.kartenRollen.join(", ")})`); +/* ABGELEITET, NICHT GEZAEHLT (berichtigt 22.09.2026). + --------------------------------------------------------------------- + Hier stand `=== 7` und eine abgeschriebene Liste von sieben Namen. + Am 21.09. kam die Rolle "linke" dazu, und beide Zeilen wurden rot, + obwohl das Formular richtig war -- gemessen acht Karten, erwartet + sieben. Die Pruefung war einen Tag lang rot und hat dabei nichts + gefunden ausser sich selbst. + + Die eigentliche Aussage ist auch eine andere: Das Formular soll + GENAU DAS anbieten, was der Server auch annimmt. Zwei Listen an zwei + Stellen sind zwei Gelegenheiten, eine davon zu vergessen -- genau + daran ist es am 17.09. schon einmal gescheitert ("wieso kann ich + immer noch keine community rolle erstellen?"). */ +const w = await import("./workspace.js"); +const sollKarten = [...w.darfAnlegen({ rolle: "admin", haus: "agentur" })].sort(); +ok(mass.karten === sollKarten.length, + `alle ${sollKarten.length} vergebbaren Rollen stehen zur Wahl (${mass.karten})`); +ok(JSON.stringify([...mass.kartenRollen].sort()) === JSON.stringify(sollKarten), + `und es sind genau die, die der Server annimmt (${mass.kartenRollen.join(", ")})`); ok(!mass.kartenRollen.includes("admin"), "DogFather steht NICHT zur Wahl -- auch nicht fuer DogFather"); @@ -413,6 +428,164 @@ const ERWARTET = 17; console.log(""); ok(geprueft >= ERWARTET, `es sind ${geprueft} Prüfungen gelaufen (erwartet mindestens ${ERWARTET})`); +/* =================================================================== + TEIL: DIE RECHTE HAND LEGT SELBST JEMANDEN AN (22.09.2026) + =================================================================== + + Filipe: "dan will ich dass die rechte hand auch neue personen + hinzufuegen kann ... und die codes genau so sieht wie dogfather, + damit sie das auch machen kann wenn er live ist." + + GEPRUEFT WIRD DER GANZE WEG, nicht die Rechtetabelle. Die sagt seit + heute "ja"; ob ein Mensch damit jemanden anlegen kann, ist eine + andere Frage. Beim ersten Anlauf war sie mit "nein" zu beantworten: + Die Seite entschied den Sendeweg an `ich.rolle === 'admin'`, und + fuer die rechte Hand gab es damit GAR KEINEN -- sie bekam "Fuer die + Rolle modi gibt es hier keinen Weg", einen Satz, der wie ein Fehler + im Formular klingt. + =================================================================== */ +console.log("\n— Die rechte Hand legt jemanden an —"); +{ + /* EIGENER BROWSER AUF DER CREW-ADRESSE. + ------------------------------------------------------------------ + 127.0.0.1 ist die AGENTURWAND -- dort gibt es die Kachel "rechte + Hand" gar nicht, und der erste Anlauf lief in eine + Zeitueberschreitung. Das war kein Befund, sondern die falsche Tuer. + + Chromium zwingt `crew.dogfather-universe.com` auf https (die + Adresse steht in seiner eingebauten HSTS-Liste), deshalb ein + Vorbau mit eigenem Zertifikat -- derselbe Weg wie in + pruef-handy-teamdogi und pruef-zuteilung. */ + const { execFileSync } = await import("node:child_process"); + const { createServer: httpsServer } = await import("node:https"); + const { request: httpAnfrage } = await import("node:http"); + const { readFileSync: lesen } = await import("node:fs"); + const HOST = "crew.dogfather-universe.com"; + const sk = join(ordner, "pf.key"), zt = join(ordner, "pf.crt"); + execFileSync("openssl", ["req", "-x509", "-newkey", "rsa:2048", "-nodes", + "-keyout", sk, "-out", zt, "-days", "2", "-subj", `/CN=${HOST}`, + "-addext", `subjectAltName=DNS:${HOST}`], { stdio: "ignore" }); + const HP = PORT + 1; + const vorbau = httpsServer({ key: lesen(sk), cert: lesen(zt) }, (von, nach) => { + const w = httpAnfrage({ host: "127.0.0.1", port: PORT, path: von.url, + method: von.method, headers: { ...von.headers, host: `${HOST}:${HP}` } }, + (a) => { nach.writeHead(a.statusCode || 502, a.headers); a.pipe(nach); }); + von.pipe(w); + }); + await new Promise((r) => vorbau.listen(HP, "127.0.0.1", r)); + const CREW = `https://${HOST}:${HP}`; + const crewBrowser = await chromium.launch({ + args: [`--host-resolver-rules=MAP ${HOST} 127.0.0.1`, "--ignore-certificate-errors"], + }); + const kontext = await crewBrowser.newContext({ viewport: { width: 1440, height: 1000 } }); + const hand = await kontext.newPage(); + try { + await hand.goto(CREW + "/workspace/", { waitUntil: "domcontentloaded" }); + await hand.click('.rolle[data-rolle="hand"]'); + await hand.fill("#code", "CODE-HAND-0001"); + await hand.click("button[type=submit]"); + await hand.waitForURL("**/start.html", { timeout: 20000 }); + await hand.goto(CREW + "/workspace/personen.html", { waitUntil: "networkidle" }); + await hand.waitForTimeout(900); + await hand.click("#neu-oeffnen").catch(() => {}); + await hand.waitForTimeout(500); + + const bild = await hand.evaluate(async () => { + const a = await fetch("/workspace/api/ich").then((r) => r.json()).catch(() => ({})); + const f = document.getElementById("neu"); + const auf = document.getElementById("neu-oeffnen"); + return { + formDa: !!f && !f.hidden, + knopfDa: !!auf && !auf.hidden, + rollen: [...document.querySelectorAll("#neu .rollenwahl__knopf")] + .map((k) => k.dataset.rolle || k.getAttribute("data-rolle")).filter(Boolean), + woSonst: [...document.querySelectorAll(".rollenwahl__knopf")] + .map((k) => (k.closest("[id]") || {}).id + ":" + (k.dataset.rolle || "?")), + vomServer: a.darf_anlegen, + meineRolle: a.rolle, + }; + }); + console.log(" /api/ich sagt: rolle=" + bild.meineRolle + + " darf_anlegen=" + JSON.stringify(bild.vomServer) + + " Knopf=" + bild.knopfDa + " Form offen=" + bild.formDa); + console.log(" Rollenknoepfe: " + JSON.stringify(bild.woSonst)); + ok(bild.formDa, "sie bekommt das Formular ueberhaupt zu sehen"); + ok(bild.rollen.length > 0 && bild.rollen.every((r) => ["modi", "gast"].includes(r)), + `und genau die Rollen, die sie darf (${bild.rollen.join(", ") || "keine"})`); + + /* JETZT WIRKLICH ANLEGEN. Ein Formular, das dasteht und beim + Absenden scheitert, ist schlimmer als keines. */ + const name = "Neue Modi " + Date.now().toString().slice(-5); + await hand.evaluate((n) => { + const k = [...document.querySelectorAll(".rollenwahl__knopf")] + .find((x) => (x.dataset.rolle || "") === "modi"); + if (k) k.click(); + document.getElementById("f-name").value = n; + }, name); + await hand.waitForTimeout(250); + await hand.click("#neu button[type=submit]").catch(async () => { + await hand.evaluate(() => document.getElementById("neu").requestSubmit()); + }); + await hand.waitForTimeout(2200); + + /* DIE ABSCHNITTE DER LISTE SIND ZUGEKLAPPT -- `innerText` sieht + zugeklappten Inhalt nicht. Dieselbe Falle wie am 21.09. bei + pruef-nachfrage. Erst aufklappen, dann messen. */ + await hand.evaluate(() => { + for (const d of document.querySelectorAll("details")) d.open = true; + }); + await hand.waitForTimeout(400); + const danach = await hand.evaluate((n) => { + const kasten = document.querySelector(".code-kasten, #code-kasten"); + const text = document.body.innerText; + return { + fehler: (document.getElementById("neu-fehler") || {}).textContent || "", + codeDa: !!kasten && !kasten.hidden, + codeText: kasten ? (kasten.innerText || "").slice(0, 200) : "", + stehtInListe: text.includes(n), + listeDa: !!document.getElementById("liste"), + listeText: (document.getElementById("liste") || {}).innerText + ? document.getElementById("liste").innerText.replace(/\s+/g, " ").slice(-260) : "(leer)", + gesucht: n, + }; + }, name); + ok(!danach.fehler, `kein Fehler beim Absenden (${danach.fehler || "keiner"})`); + ok(danach.codeDa, "der Zugangscode wird ihr angezeigt"); + ok(/[A-Z0-9]{4}/.test(danach.codeText), + `und er sieht auch wie einer aus (${danach.codeText.replace(/\s+/g, " ").slice(0, 60)})`); + /* GEMESSEN WIRD DIE LISTE DES SERVERS, NICHT DER SICHTBARE TEXT + (berichtigt 22.09.2026). + + Hier stand `document.body.innerText.includes(name)`. Die + Abschnitte der Personenliste sind zugeklappt und zeigen nur die + Anfangsbuchstaben -- der volle Name steht dort also gar nicht, + obwohl die Person laengst angelegt ist. Die Zeile war rot, und + kaputt war nur sie selbst. + + Jetzt wird gefragt, was sie WIRKLICH bekommt: dieselbe Auskunft, + aus der die Liste gebaut wird. Das beweist beides auf einmal -- + dass sie anlegen kann UND dass sie das Ergebnis sieht. */ + const ausListe = await hand.evaluate(async (n) => { + const a = await fetch("/workspace/api/verwaltung/personen") + .then((r) => r.json()).catch(() => null); + return { + code: Array.isArray(a?.personen) ? 200 : 0, + dabei: (a?.personen || []).some((x) => x.name === n), + zahl: (a?.personen || []).length, + }; + }, name); + ok(ausListe.code === 200, + `sie bekommt die Personenliste (${ausListe.zahl} Menschen)`); + ok(ausListe.dabei, ausListe.dabei + ? "und die eben angelegte Person steht darin" + : `die eben angelegte Person fehlt in ihrer Liste (${name})`); + } finally { + await kontext.close(); + await crewBrowser.close(); + await new Promise((r) => vorbau.close(r)); + } +} + await browser.close(); try { rmSync(ordner, { recursive: true, force: true }); } catch { /* egal */ } console.log(`\n${fehler ? "FEHLER: " + fehler : "Alles in Ordnung"} — ${geprueft} Prüfungen`); diff --git a/server/workspace-personen.js b/server/workspace-personen.js index e5ed89f7..f65574f3 100644 --- a/server/workspace-personen.js +++ b/server/workspace-personen.js @@ -128,6 +128,36 @@ function nurAdmin(req, res, next) { WELCHE Rolle sie vergeben darf, steht NICHT hier -- das entscheidet ANLEGBAR in der Route. Diese Zeile oeffnet nur die Tuer. */ + /* DIE RECHTE HAND LEGT PERSONEN AN UND SIEHT IHRE CODES (22.09.2026). + + Filipe: "damit sie das auch machen kann wenn er live ist." + + NUR DIE RECHTE, NICHT DIE LINKE. `istHand()` wuerde beide treffen; + fuer die linke Hand ist "legt niemanden an" eine ausdrueckliche + Entscheidung vom 21.09. Deshalb steht hier die Rolle und nicht der + Sammelbegriff -- der haette die Entscheidung stillschweigend + umgedreht. + + ZWEI WEGE, NICHT DIE GANZE VERWALTUNG: anlegen und einen Code neu + erzeugen. Sperren, Loeschen, Betreuung und Protokoll bleiben bei + DogFather. Und WELCHE Rolle sie anlegen darf, entscheidet nicht + diese Zeile, sondern ANLEGBAR in der Route -- diese Tuer oeffnet + nur den Weg. + + WARUM AUCH "Code neu erzeugen": Ein Code wird genau einmal + angezeigt. Geht er verloren, ist der Zugang ohne diesen Weg tot -- + und dann muesste doch wieder DogFather ran, also genau das, was + nicht sein soll. */ + const anlegeWeg = req.method === "POST" + && req.baseUrl + req.path === "/workspace/api/verwaltung/personen"; + const codeWeg = req.method === "POST" + && /^\/workspace\/api\/verwaltung\/personen\/[0-9]+\/code$/ + .test(req.baseUrl + req.path); + if (person.rolle === "hand" && (anlegeWeg || codeWeg)) { + req.person = person; + return next(); + } + const rollenWeg = req.method === "PUT" && /^\/workspace\/api\/verwaltung\/personen\/[0-9]+\/rolle$/ .test(req.baseUrl + req.path); @@ -169,6 +199,25 @@ function nurDogFatherBeiLeitung(req, res, next) { const id = Number(req.params.id); if (!Number.isInteger(id)) return next(); const ziel = db().prepare("SELECT rolle FROM personen WHERE id = ?").get(id); + + /* DIE RECHTE HAND NUR AN DENEN, DIE SIE AUCH ANLEGEN DUERFTE + (22.09.2026). + + Ohne diese Zeile koennte sie den Code einer LINKEN HAND neu + erzeugen -- und haette damit einen Zugang, der fast so viel darf + wie sie selbst, in der Hand. Das ist nicht gemeint und waere auch + nicht aufgefallen: Die Schranke darunter kennt nur "admin" und + "manager". + + Gefragt wird dieselbe Liste wie beim Anlegen. Eine zweite waere + die, die beim naechsten Umbau auseinanderlaeuft. */ + if (req.person?.rolle === "hand" && ziel + && !darfAnlegen(req.person).includes(ziel.rolle)) { + return res.status(403).json({ + fehler: "An dieser Rolle ändert die rechte Hand nichts.", + }); + } + if (ziel && (ziel.rolle === "admin" || ziel.rolle === "manager")) { return res.status(403).json({ fehler: "An DogFather und Managern ändert nur DogFather etwas.", diff --git a/server/workspace.js b/server/workspace.js index bad63857..274915ac 100644 --- a/server/workspace.js +++ b/server/workspace.js @@ -452,6 +452,24 @@ const ANLEGBAR = { spicy: ["spicy", "manager", "scout", "creator"], /* Ein Manager stellt Creator ein, die er dann auch betreut. */ manager: ["creator"], + /* DIE RECHTE HAND LEGT PERSONEN AN (22.09.2026). + + Filipe: "dan will ich dass die rechte hand auch neue personen + hinzufuegen kann. also neue erstellen kann und die codes genau so + sieht wie dogfather, damit sie das auch machen kann wenn er live + ist." + + DIESELBE LISTE, DIE SIE AUCH VERGEBEN DARF -- abgeleitet aus + ROLLEN_ZUM_AENDERN, nicht danebengeschrieben. Zwei Listen mit + denselben zwei Rollen waeren zwei Gelegenheiten, eine davon zu + aendern und die andere zu vergessen; dann duerfte sie eine Rolle + anlegen, aber nicht vergeben, und niemand wuesste warum. + + WAS DAMIT AUSDRUECKLICH NICHT GEHT: eine zweite rechte Hand, eine + linke Hand oder einen zweiten DogFather. Sie kann sich also auch + ueber den Umweg "neuen Zugang anlegen" keine hoeheren Rechte + verschaffen. */ + hand: ROLLEN_ZUM_AENDERN.hand, /* DIE LINKE HAND LEGT NIEMANDEN AN (21.09.2026) -- ausdruecklich im Auftrag. Sie stuende auch ohne diese Zeile auf [] (darfAnlegen nimmt `?? []`), aber dann saehe es aus wie vergessen. Eine diff --git a/workspace/anruf-probe.html b/workspace/anruf-probe.html index 9c14d79f..9c9cc12b 100644 --- a/workspace/anruf-probe.html +++ b/workspace/anruf-probe.html @@ -16,15 +16,15 @@ verdeckt. Gefunden hat es pruef-struktur. Richtig sind `gate.css` (die Farbwerte des Hauses) und `haus.css`. --> - - + + - +