Spicy Media legt Manager UND Scouts an -- eine Liste statt vier
Filipe, mit Bildschirmfoto der Zugaenge-Seite: "die spicy rolle soll auch manager und scouts hinzufuegen koennen." DER MANAGER-KNOPF FEHLTE NICHT AUS RECHTEGRUENDEN. Serverseitig war die Tuer /workspace/api/manager-anlegen fuer Spicy Media die ganze Zeit offen. Es gab nur nichts zum Draufdruecken -- wegen ZWEIER Listen in derselben Funktion, drei Zeilen auseinander (personen.js): const darf = ... spicy ? ['manager', 'creator'] : ['creator']; ... if ((r.wert === 'admin' || r.wert === 'manager') && ich.rolle !== 'admin') continue; Die erste erlaubt den Manager, die zweite nimmt ihn wieder weg. Uebrig blieb ein einziger Knopf: Creator. Nichts war kaputt, nichts wurde rot, es fehlte einfach -- die Sorte Fehler, die nur jemandem auffaellt, der davorsitzt. FUER SCOUTS GAB ES UEBERHAUPT KEINE TUER. Nur DogFather konnte welche anlegen. Und die Wegwahl in der Oberflaeche war eine Kette mit Auffangbecken (`rolle === 'manager' ? ... : creator-anlegen`): Ein Scout waere im else gelandet, und creator-anlegen legt IMMER einen Creator an. Der Knopf haette Erfolg gemeldet und das Falsche getan. DIE ANTWORT STEHT JETZT AN EINER STELLE. `darfAnlegen` in workspace.js sagt, wer wen anlegen darf. Daraus lesen: - die beiden Team-Tueren (Manager, Scout) - die allgemeine Verwaltungs-Tuer von DogFather - die Oberflaeche, ueber `darf_anlegen` in /workspace/api/ich Die Oberflaeche hat damit gar keine eigene Liste mehr und kann deshalb auch nicht mehr abweichen -- weder zu streng noch zu grosszuegig. ZWEI TUEREN, NICHT EINE MIT EINEM ROLLENFELD. Der Absatz an der Manager-Tuer raet davon ab, und der Rat gilt: Eine Tuer, die NICHTS anderes kann, als eine bestimmte Rolle anzulegen, ist sicherer als eine, die vorher nachfragt. `teamTuer(rolle)` baut beide aus demselben Text -- die Rolle wird beim Einhaengen festgelegt und kommt nie aus dem Aufruf. Geprueft: ein mitgeschicktes "rolle: admin" bleibt wirkungslos. GEPRUEFT (pruef-creator-anlegen, 33 -> 49 Pruefungen) - Spicy Media legt Manager an -> 201, Rolle stimmt - Spicy Media legt Scout an -> 201, Rolle stimmt - "rolle: admin" mitgeschickt -> wirkungslos, es wird ein Scout - ein Manager durch die Scout-Tuer -> 404 - ein Scout durch die Scout-Tuer -> 404 - Personenliste lesen -> 200 (die eine gewollte Ausnahme) - darueber anlegen -> 404, und es entsteht niemand - /api/ich nennt Spicy: manager, scout, creator -- und keinen DogFather - ein Manager bekommt genau eine Rolle genannt, ein Scout keine - die Knoepfe auf der Seite stimmen mit alldem ueberein - DogFather sieht unveraendert alle -- gemessen, nicht geglaubt Der erste Anlauf der Pruefung behauptete, Spicy Media komme gar nicht an /workspace/api/verwaltung. Falsch, und sie wurde zu Recht rot: nurAdmin laesst genau einen Fall durch, das LESEN der Personenliste. Diese Trennung ist jetzt festgenagelt. Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
@@ -97,6 +97,9 @@ let idDogi, idMax, idMia, idScoutMax, idScoutMia, idCreator;
|
||||
idScoutMax = anlegen(d, "SamVonMax", "scout", "CODE-SAM-00001");
|
||||
idScoutMia = anlegen(d, "TimVonMia", "scout", "CODE-TIM-00001");
|
||||
idCreator = anlegen(d, "Luna", "creator", "CODE-LUNA-0001");
|
||||
/* Seit dem 10.09.2026 gehoert Spicy Media dazu: Sie darf Manager UND
|
||||
Scouts anlegen, und genau das steht im Abschnitt 6. */
|
||||
anlegen(d, "Agentur", "spicy", "CODE-SPIC-0001");
|
||||
d.prepare("INSERT INTO scout_zuteilung (scout_id, manager_id, seit) VALUES (?,?,?)")
|
||||
.run(idScoutMax, idMax, jetzt);
|
||||
d.prepare("INSERT INTO scout_zuteilung (scout_id, manager_id, seit) VALUES (?,?,?)")
|
||||
@@ -118,6 +121,7 @@ const keksMax = await anmelden("manager", "CODE-MAX-00001");
|
||||
const keksMia = await anmelden("manager", "CODE-MIA-00001");
|
||||
const keksScout = await anmelden("scout", "CODE-SAM-00001");
|
||||
const keksLuna = await anmelden("creator", "CODE-LUNA-0001");
|
||||
const keksSpicy = await anmelden("spicy", "CODE-SPIC-0001");
|
||||
|
||||
const ruf = async (art, weg, keks, koerper) => {
|
||||
const a = await fetch(BASIS + weg, { method: art,
|
||||
@@ -301,6 +305,145 @@ console.log("\n=== Der Knopf auf dem Dashboard ===");
|
||||
await browser.close();
|
||||
}
|
||||
|
||||
/* =======================================================================
|
||||
6. SPICY MEDIA LEGT MANAGER UND SCOUTS AN (10.09.2026)
|
||||
|
||||
Filipe, mit Bildschirmfoto: "die spicy rolle soll auch manager und
|
||||
scouts hinzufuegen koennen."
|
||||
|
||||
Der Fehler davor war kein fehlendes Recht, sondern ZWEI Listen, die
|
||||
einander widersprachen: Die Oberflaeche erlaubte Spicy Media in einer
|
||||
Zeile den Manager und nahm ihn drei Zeilen spaeter wieder weg. Fuer
|
||||
Scouts gab es ueberhaupt keine Tuer.
|
||||
|
||||
Deshalb wird hier BEIDES geprueft — dass es geht, und dass die
|
||||
Oberflaeche dieselbe Antwort bekommt wie der Server. Eine der beiden
|
||||
Pruefungen allein haette den Fehler nicht gefunden: Serverseitig war
|
||||
der Manager ja die ganze Zeit erlaubt.
|
||||
======================================================================= */
|
||||
console.log("\n=== Spicy Media legt Manager und Scouts an ===");
|
||||
{
|
||||
const { status, daten } = await ruf("POST", "/workspace/api/manager-anlegen",
|
||||
keksSpicy, { name: "NeuerManager" });
|
||||
ok(status === 201, `ein Manager entsteht (HTTP ${status})`);
|
||||
ok(daten?.rolle === "manager", `und ist wirklich ein Manager (${daten?.rolle})`);
|
||||
}
|
||||
{
|
||||
const { status, daten } = await ruf("POST", "/workspace/api/scout-anlegen",
|
||||
keksSpicy, { name: "NeuerScout" });
|
||||
ok(status === 201, `ein Scout entsteht (HTTP ${status})`);
|
||||
/* DIE ROLLE IST HIER DER GANZE PUNKT. Vor dem Umbau waere die
|
||||
Oberflaeche mit "scout" beim Creator-Weg gelandet, und der legt
|
||||
IMMER einen Creator an -- der Knopf haette Erfolg gemeldet und das
|
||||
Falsche getan. */
|
||||
ok(daten?.rolle === "scout", `und ist wirklich ein Scout (${daten?.rolle})`);
|
||||
}
|
||||
{
|
||||
/* Die Rolle kommt NICHT aus dem Aufruf: Wer sie mitschickt, aendert
|
||||
nichts. Die Tuer kennt genau eine. */
|
||||
const { status, daten } = await ruf("POST", "/workspace/api/scout-anlegen",
|
||||
keksSpicy, { name: "MoechtegernChef", rolle: "admin" });
|
||||
ok(status === 201 && daten?.rolle === "scout",
|
||||
`ein mitgeschicktes "rolle: admin" bleibt wirkungslos (${daten?.rolle})`);
|
||||
}
|
||||
{
|
||||
const { status } = await ruf("POST", "/workspace/api/scout-anlegen",
|
||||
keksMax, { name: "ScoutVonMax" });
|
||||
ok(status === 404, `ein Manager kommt durch diese Tuer nicht (HTTP ${status})`);
|
||||
}
|
||||
{
|
||||
const { status } = await ruf("POST", "/workspace/api/scout-anlegen",
|
||||
keksScout, { name: "ScoutVomScout" });
|
||||
ok(status === 404, `ein Scout auch nicht (HTTP ${status})`);
|
||||
}
|
||||
/* DIE AUSNAHME, DIE ES WIRKLICH GIBT — und ihre Grenze.
|
||||
|
||||
Erster Anlauf dieser Pruefung behauptete, Spicy Media komme gar nicht
|
||||
an /workspace/api/verwaltung. Das war falsch, und die Pruefung wurde
|
||||
zu Recht rot: `nurAdmin` laesst genau EINEN Fall durch, das LESEN der
|
||||
Personenliste ("spicy soll genau das sehen koennen"). Ueberblick ist
|
||||
nicht Verwaltung — und genau diese Trennung gehoert festgenagelt,
|
||||
sonst weitet sie sich beim naechsten Umbau unbemerkt aus. */
|
||||
{
|
||||
const { status } = await ruf("GET", "/workspace/api/verwaltung/personen", keksSpicy);
|
||||
ok(status === 200, `die Personenliste darf Spicy Media LESEN (HTTP ${status})`);
|
||||
}
|
||||
{
|
||||
const { status } = await ruf("POST", "/workspace/api/verwaltung/personen",
|
||||
keksSpicy, { name: "AufDemKurzenWeg", rolle: "admin" });
|
||||
ok(status === 404, `aber nicht darueber anlegen (HTTP ${status})`);
|
||||
const z = new DatabaseSync(DB).prepare(
|
||||
"SELECT rolle FROM personen WHERE name = ?").get("AufDemKurzenWeg");
|
||||
ok(!z, "und es entsteht dabei auch niemand");
|
||||
}
|
||||
|
||||
/* ---- Und die Oberflaeche fragt dieselbe Stelle ---------------------- */
|
||||
{
|
||||
const { daten } = await ruf("GET", "/workspace/api/ich", keksSpicy);
|
||||
const darf = daten?.darf_anlegen || [];
|
||||
ok(darf.includes("manager") && darf.includes("scout") && darf.includes("creator"),
|
||||
`/api/ich nennt Spicy Media: ${darf.join(", ")}`);
|
||||
/* DAS WICHTIGERE: was NICHT drinsteht. Ein Knopf zu viel waere hier
|
||||
schlimmer als einer zu wenig -- er verspraeche ein Recht, das es
|
||||
nicht gibt. */
|
||||
ok(!darf.includes("admin"), "und keinen DogFather");
|
||||
}
|
||||
{
|
||||
const { daten } = await ruf("GET", "/workspace/api/ich", keksMax);
|
||||
const darf = daten?.darf_anlegen || [];
|
||||
ok(darf.length === 1 && darf[0] === "creator",
|
||||
`ein Manager bekommt genau eine Rolle genannt: ${darf.join(", ") || "keine"}`);
|
||||
}
|
||||
{
|
||||
const { daten } = await ruf("GET", "/workspace/api/ich", keksScout);
|
||||
const darf = daten?.darf_anlegen || [];
|
||||
ok(darf.length === 0, `ein Scout bekommt keine genannt (${darf.length})`);
|
||||
}
|
||||
|
||||
/* ---- Die Knoepfe auf der Zugaenge-Seite ----------------------------- */
|
||||
console.log("\n=== Die Rollenknoepfe auf der Zugaenge-Seite ===");
|
||||
{
|
||||
const pw = await import("file:///C:/Users/qciga/Documents/Obelix/Analyse/node_modules/playwright/index.mjs");
|
||||
const browser = await pw.chromium.launch();
|
||||
const knoepfeFuer = async (rolle, code) => {
|
||||
const ctx = await browser.newContext({ viewport: { width: 1400, height: 900 } });
|
||||
const seite = await ctx.newPage();
|
||||
await seite.goto(BASIS + "/workspace/", { waitUntil: "networkidle" });
|
||||
await seite.click(`.rolle[data-rolle="${rolle}"]`);
|
||||
await seite.fill("#code", code);
|
||||
await seite.click("button[type=submit]");
|
||||
await seite.waitForURL("**/start.html", { timeout: 25000 });
|
||||
await seite.goto(BASIS + "/workspace/personen.html", { waitUntil: "networkidle" });
|
||||
await seite.waitForTimeout(1600);
|
||||
const liste = await seite.$$eval(".rollenwahl__knopf",
|
||||
(ks) => ks.map((k) => k.dataset.rolle)).catch(() => []);
|
||||
await ctx.close();
|
||||
return liste;
|
||||
};
|
||||
const spicy = await knoepfeFuer("spicy", "CODE-SPIC-0001");
|
||||
ok(spicy.includes("manager"), `Spicy Media sieht den Manager-Knopf (${spicy.join(", ")})`);
|
||||
ok(spicy.includes("scout"), "und den Scout-Knopf");
|
||||
ok(spicy.includes("creator"), "und den Creator-Knopf");
|
||||
ok(!spicy.includes("admin"), "aber keinen DogFather-Knopf");
|
||||
/* GEGENPROBE: Die Zaehlung erkennt einen fehlenden Knopf wirklich.
|
||||
Beim Manager MUSS genau einer stehen -- stuenden dort drei, waere
|
||||
die Messung oben wertlos. */
|
||||
const managerKnoepfe = await knoepfeFuer("manager", "CODE-MAX-00001");
|
||||
ok(managerKnoepfe.length === 1 && managerKnoepfe[0] === "creator",
|
||||
`ein Manager sieht genau einen: ${managerKnoepfe.join(", ")}`);
|
||||
/* UND BEI DOGFATHER AENDERT SICH NICHTS. Er bekommt jetzt eine
|
||||
laengere Liste vom Server (auch die verborgenen Rollen), die
|
||||
Knopfliste der Seite kennt aber nur die fuenf sichtbaren -- der
|
||||
Schnitt der beiden ist derselbe wie vorher. Das ist eine Behauptung
|
||||
ueber MEINE Aenderung, also gehoert sie gemessen und nicht
|
||||
geglaubt. */
|
||||
const dogiKnoepfe = await knoepfeFuer("admin", "CODE-DOGI-0001");
|
||||
ok(dogiKnoepfe.length >= 5 && ["spicy", "admin", "manager", "scout", "creator"]
|
||||
.every((r) => dogiKnoepfe.includes(r)),
|
||||
`DogFather sieht weiterhin alle fuenf: ${dogiKnoepfe.join(", ")}`);
|
||||
await browser.close();
|
||||
}
|
||||
|
||||
kind.kill();
|
||||
await new Promise((r) => setTimeout(r, 400));
|
||||
try { rmSync(ordner, { recursive: true, force: true }); } catch { /* Zugabe */ }
|
||||
|
||||
Reference in New Issue
Block a user