From e3aeeb01cde0b32fb0ecc7590befcfecaa887c45 Mon Sep 17 00:00:00 2001 From: Dogfather Date: Sat, 12 Sep 2026 00:25:47 +0200 Subject: [PATCH] Rollen wechseln: auch Spicy Media -- und DogFather ist nicht mehr vergebbar Filipe: "ich will dass die rolle spicy und dogfather, auch die rollen wechseln koennen wenn die personen schon drin sind. von alle kategorien, creator, scouts, manager spicy. dogfather soll man nicht auswaehlen koennen. das ist die einzige die man nicht auswaehlen kann bitte." ZWEI AENDERUNGEN, BEIDE IN EINER LISTE (ANLEGBAR): admin: alles AUSSER der eigenen Rolle spicy: spicy, manager, scout, creator (vorher ohne spicy) Weil die Oberflaeche ihre Knoepfe aus derselben Auskunft baut (`darf_anlegen` in /api/ich), verschwindet DogFather damit von selbst aus JEDER Auswahl -- beim Anlegen wie beim Wechseln, bei Spicy Media wie bei DogFather. Eine Liste, zwei Formulare, kein Nachziehen. WAS DAS BEDEUTET, damit es niemand spaeter sucht: Es laesst sich kein zweiter DogFather-Zugang mehr anlegen und niemand mehr zu einem befoerdern. Der bestehende ist durch Sicherung 3 geschuetzt (nie den letzten herabstufen) und kann nicht versehentlich verschwinden. Zurueckdrehen laesst sich das nur in ANLEGBAR. DIE TUER: /verwaltung haengt an nurAdmin, und dort steht jetzt eine DRITTE enge Ausnahme -- PUT auf genau /personen//rolle, fuer genau die Rollen aus darfRollenWechseln(). Gleiche Bauweise wie die beiden davor (Liste fuer Spicy Media, Liste fuer die rechte Hand). Was NICHT mitgeht: Codes, Sperren, Loeschen, Zuteilung, Protokoll. EINE NEUE SICHERUNG, weil sich die Tuer geoeffnet hat: An einer DogFather-Zeile aendert nur DogFather. Die bestehenden Pruefungen sehen auf die ZIEL-Rolle ("darfst du 'manager' vergeben?") -- dass die BETROFFENE Person DogFather ist, kam darin bis heute nicht vor. Sicherung 3 haette es heute zufaellig abgefangen, weil es genau einen gibt; eine Sperre, die nur wegen einer Zahl im Bestand haelt, ist keine. DIE OBERFLAECHE: "Rolle aendern" und "Loeschen" hingen an EINER Zeile (`ich.rolle === 'admin'`). Sie gehoeren nicht zusammen -- Loeschen bleibt bei DogFather. Und die CSS-Regel, die fuer Spicy Media die ganze Knopfreihe ausblendete, ist weg: Welche Knoepfe es gibt, entscheidet jetzt personen.js, und was nicht entsteht, muss man nicht verstecken. pruef-spicy 62 -> 83. Gemessen wird jede der vier Kategorien EINZELN (waere nur eine offen, saehe "geht" genauso aus), dazu: admin weder von Spicy Media noch von DogFather vergebbar, an DogFathers Zeile aendert sie nichts (und er ist danach nachweislich noch admin), ein Manager kommt an den Weg nicht, loeschen bleibt zu -- und im Browser, dass der KNOPF da ist, nicht nur das Recht. Genau daran war heute frueh im Chat eine Stunde draufgegangen. Dabei zwei eigene Messfehler gefunden: Die Knoepfe entstehen erst in einer AUFGEKLAPPTEN Kategorie (vorher zu frueh gemessen), und /api/ich wird jetzt als Vorbedingung geprueft. DREI PRUEFUNGEN GEDREHT, KEINE GELOESCHT: - pruef-personen-formular: 7 Karten, `admin` fehlt (eigene Aussage). Die Zeichenpruefung verglich die rechte Hand gegen die Admin-KARTE -- die es nicht mehr gibt; sie lief gegen `undefined`. Ersatz ist das Zeichen selbst, und der Kommentar sagt, dass das schwaecher ist. - pruef-haus-trennung: Der zweite DogFather entsteht jetzt im Bestand statt ueber die Schnittstelle, und DASS die Schnittstelle ihn ablehnt, ist der erste Prueffall geworden. Sonst waere "nie den letzten DogFather" ab heute ungeprueft -- weil ihre Voraussetzung schwerer herzustellen ist. - pruef-creator-anlegen: aus einer Aussage zwei (die vier sind da UND admin fehlt). Gruen: personen-liste, personen-kachel, verborgen, manager-sicht, creator-anlegen, haus-trennung, personen-formular, spicy, rollen. Co-Authored-By: Claude Opus 5 --- server/pruef-creator-anlegen.mjs | 23 +++-- server/pruef-haus-trennung.mjs | 33 +++++-- server/pruef-personen-formular.mjs | 32 +++++-- server/pruef-spicy.mjs | 137 +++++++++++++++++++++++++++++ server/workspace-personen.js | 54 +++++++++++- server/workspace.js | 59 ++++++++++++- workspace/app.webmanifest | 8 +- workspace/assets/css/personen.css | 6 +- workspace/assets/js/personen.js | 64 ++++++++++++-- workspace/aufgaben.html | 24 ++--- workspace/automation.html | 26 +++--- workspace/bereich.html | 34 +++---- workspace/calls.html | 28 +++--- workspace/chat.html | 26 +++--- workspace/content.html | 30 +++---- workspace/crew-index.html | 10 +-- workspace/crew.webmanifest | 8 +- workspace/dateien.html | 26 +++--- workspace/entwicklung.html | 24 ++--- workspace/index.html | 8 +- workspace/kalender.html | 28 +++--- workspace/leistung.html | 26 +++--- workspace/personen.html | 26 +++--- workspace/profil.html | 28 +++--- workspace/rechte.html | 24 ++--- workspace/report.html | 28 +++--- workspace/scouting.html | 26 +++--- workspace/start.html | 24 ++--- workspace/startcheck.html | 28 +++--- workspace/steckbrief.html | 26 +++--- workspace/talente.html | 24 ++--- workspace/team.html | 26 +++--- workspace/teamlage.html | 24 ++--- workspace/treff-moderation.html | 24 ++--- workspace/treff-regeln.html | 24 ++--- workspace/uebersicht.html | 26 +++--- workspace/wissen.html | 26 +++--- 37 files changed, 718 insertions(+), 380 deletions(-) diff --git a/server/pruef-creator-anlegen.mjs b/server/pruef-creator-anlegen.mjs index 354ff552..bc41d588 100644 --- a/server/pruef-creator-anlegen.mjs +++ b/server/pruef-creator-anlegen.mjs @@ -431,16 +431,21 @@ console.log("\n=== Die Rollenknoepfe auf der Zugaenge-Seite ==="); 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. */ + /* BEI DOGFATHER FEHLT SEIT DEM 11.09.2026 GENAU EINE: seine eigene. + + Filipe: "dogfather soll man nicht auswaehlen koennen. das ist die + einzige die man nicht auswaehlen kann bitte." Hier stand + `["spicy","admin","manager","scout","creator"].every(...)` -- die + Zeile war richtig, bis die Rolle aus ANLEGBAR fiel. + + ZWEI AUSSAGEN STATT EINER: Die vier muessen DA sein, und `admin` + muss FEHLEN. Nur "vier sind da" waere auch dann gruen, wenn admin + wieder auftauchte. */ 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(", ")}`); + ok(["spicy", "manager", "scout", "creator"].every((r) => dogiKnoepfe.includes(r)), + `DogFather sieht die vier vergebbaren: ${dogiKnoepfe.join(", ")}`); + ok(!dogiKnoepfe.includes("admin"), + "seine eigene Rolle steht NICHT zur Wahl -- auch bei ihm nicht"); await browser.close(); } diff --git a/server/pruef-haus-trennung.mjs b/server/pruef-haus-trennung.mjs index 4a6f84e9..d84c2be0 100644 --- a/server/pruef-haus-trennung.mjs +++ b/server/pruef-haus-trennung.mjs @@ -465,13 +465,34 @@ console.log("=== Die Rolle aendern ==="); keks: dogi.keks, rumpf: JSON.stringify({ rolle: "creator" }) }); ok(fremd.status === 403, `auf crew. auch nicht zum Creator (${fremd.status})`); - /* DER LETZTE DOGFATHER. Es gibt genau einen -- VanVan ist in dieser - Pruefung schon die rechte Hand. Also einen zweiten anlegen, den - ersten darf man dann herabstufen, den zweiten nicht mehr. */ - const zweiter = await hole(weg, { host: WS, methode: "POST", keks: dogi.keks, + /* SEIT DEM 11.09.2026 LAESST SICH DIE ROLLE NICHT MEHR VERGEBEN. + + Filipe: "dogfather soll man nicht auswaehlen koennen. das ist die + einzige die man nicht auswaehlen kann bitte." Hier stand bis dahin + ein Anlegen ueber die Schnittstelle -- das geht jetzt nicht mehr, + und das ist der erste Prueffall geworden statt eines Hilfsschritts. */ + const versuch = await hole(weg, { host: WS, methode: "POST", keks: dogi.keks, rumpf: JSON.stringify({ name: "Zweitzugang", rolle: "admin" }) }); - const idZweit = zweiter.daten?.id; - ok(zweiter.status === 201 && idZweit > 0, `ein zweiter DogFather-Zugang (${zweiter.status})`); + ok(versuch.status === 403 || versuch.status === 400, + `ein zweiter DogFather laesst sich NICHT anlegen (${versuch.status})`); + + /* DER LETZTE DOGFATHER -- und dafuer braucht es trotzdem zwei. + + Der zweite entsteht jetzt direkt im Bestand, nicht ueber die + Schnittstelle. Das ist kein Trick an der Regel vorbei, sondern ihr + Gegenteil: Die Regel sagt "nicht ueber die Oberflaeche", und genau + das wird eine Zeile darueber nachgewiesen. Fuer die FOLGEfrage -- + darf der vorletzte herabgestuft werden? -- braucht die Pruefung + einen Bestand, den die Oberflaeche nicht mehr herstellen kann. + + Ohne diesen Umweg waere die Sicherung "nie den letzten DogFather" + ab heute ungeprueft. Eine Pruefung wegzulassen, weil ihre + Voraussetzung schwerer herzustellen ist, waere der bequeme Weg -- + und die Sicherung steht zwischen einem Versehen und einem Haus + ohne Zugang. */ + const idZweit = anlegen("Zweitzugang", "admin", "CODE-ZWEI-0001"); + ok(Number.isInteger(idZweit) && idZweit > 0, + `ein zweiter DogFather-Zugang im Bestand (#${idZweit})`); const runter = await hole(`${weg}/${idZweit}/rolle`, { host: WS, methode: "PUT", keks: dogi.keks, rumpf: JSON.stringify({ rolle: "scout" }) }); diff --git a/server/pruef-personen-formular.mjs b/server/pruef-personen-formular.mjs index bf4201f0..0f0f2372 100644 --- a/server/pruef-personen-formular.mjs +++ b/server/pruef-personen-formular.mjs @@ -154,10 +154,20 @@ const mass = await dogi.evaluate(() => { Geprüft wird ab jetzt die LISTE und nicht nur die Anzahl: Sechs Karten könnten auch fünf richtige und eine doppelte sein. */ -ok(mass.karten === 7, `alle sieben Rollen stehen zur Wahl (${mass.karten})`); +/* SECHS SEIT DEM 11.09.2026, NICHT SIEBEN. Filipe: "dogfather soll man + nicht auswaehlen koennen. das ist die einzige die man nicht + auswaehlen kann bitte." Die Karte faellt damit fuer JEDEN weg, auch + fuer DogFather selbst. + + 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(["admin", "creator", "hand", "manager", "modi", "scout", "spicy"]), + === JSON.stringify(["creator", "gast", "hand", "manager", "modi", "scout", "spicy"]), `und es sind die richtigen (${mass.kartenRollen.join(", ")})`); +ok(!mass.kartenRollen.includes("admin"), + "DogFather steht NICHT zur Wahl -- auch nicht fuer DogFather"); /* DIE STELLVERTRETUNG TRAEGT EIN EIGENES ZEICHEN. @@ -179,11 +189,19 @@ ok(JSON.stringify([...mass.kartenRollen].sort()) ist daraus eine Gruppe geworden -- Husky bei den beiden mit dem Ueberblick, Pfote bei der taeglichen Arbeit. - Verglichen wird gegen die Admin-Karte und nicht gegen "#r-husky": - Waere dort morgen ein anderes Zeichen, muesste die rechte Hand - mitwandern -- gewollt ist "dasselbe wie er", nicht "der Husky". */ -ok(mass.kartenZeichen.hand && mass.kartenZeichen.hand === mass.kartenZeichen.admin, - `die Rechte Hand trägt dasselbe Zeichen wie DogFather (${mass.kartenZeichen.hand} / ` + BIS ZUM 11.09.2026 WURDE GEGEN DIE ADMIN-KARTE VERGLICHEN, und das + war die bessere Messung: gewollt ist "dasselbe wie er", nicht "der + Husky". Seit DogFather nicht mehr vergeben werden kann, gibt es + diese Karte nicht mehr -- der Vergleich lief gegen `undefined` und + waere kommentarlos rot geblieben. + + Ersatz ist das Zeichen selbst. Das ist schwaecher, und es steht hier, + damit es niemand fuer gleichwertig haelt: Aendert jemand DogFathers + Husky, faellt es hier NICHT mehr auf. Wer die alte Staerke + zurueckwill, braucht eine Quelle fuer "DogFathers Zeichen", die + nicht an der Auswahlkarte haengt. */ +ok(mass.kartenZeichen.hand === "#r-husky", + `die Rechte Hand trägt den Husky (${mass.kartenZeichen.hand} / ` + `${mass.kartenZeichen.admin})`); /* DIE GEGENPROBE GLEICH DANEBEN: Der Modi muss sich davon unterscheiden. Ohne sie waere die Zeile darueber auch dann gruen, diff --git a/server/pruef-spicy.mjs b/server/pruef-spicy.mjs index b92483f7..b2854306 100644 --- a/server/pruef-spicy.mjs +++ b/server/pruef-spicy.mjs @@ -319,6 +319,78 @@ const ruf = async (art, weg, keks, koerper) => { ok(m.status === 201 && m.daten?.rolle === "manager", `und einen Manager (HTTP ${m.status}, ${m.daten?.rolle})`); } +{ + /* ---- ROLLEN WECHSELN (11.09.2026) ------------------------------- + Filipe: "ich will dass die rolle spicy und dogfather, auch die + rollen wechseln koennen wenn die personen schon drin sind. von + alle kategorien, creator, scouts, manager spicy. dogfather soll + man nicht auswaehlen koennen." + + AN EINEM EIGENEN MENSCHEN, nicht an Luna: Wer hier Luna umstellt, + aendert stillschweigend die Listen, die weiter unten verglichen + werden -- und der Fehlschlag stuende dann an einer Stelle, die + nichts damit zu tun hat. */ + /* VORBEDINGUNG: Die Oberflaeche baut den Knopf aus `/api/ich`. Fehlt + die Angabe dort, ist jede Aussage ueber den Knopf weiter unten + eine Aussage ueber etwas anderes. */ + const ichSpicy = await ruf("GET", "/workspace/api/ich", keksSpicy); + ok(ichSpicy.daten?.darf_rollen_wechseln === true, + `/api/ich sagt ihr, dass sie Rollen wechseln darf (${ichSpicy.daten?.darf_rollen_wechseln})`); + + const neu = await ruf("POST", "/workspace/api/creator-anlegen", keksSpicy, + { name: "Wechselkind" }); + const idWechsel = neu.daten?.id; + ok(neu.status === 201 && Number.isInteger(idWechsel), + `ein Mensch zum Umstellen ist da (#${idWechsel})`); + + const zu = async (keks, rolle, id = idWechsel) => + ruf("PUT", `/workspace/api/verwaltung/personen/${id}/rolle`, keks, { rolle }); + + /* Die vier Kategorien, die Filipe genannt hat -- einzeln, nicht als + "irgendeine geht". Waere nur eine davon offen, saehe ein "geht" + genauso aus. */ + for (const r of ["scout", "manager", "spicy"]) { + const a = await zu(keksSpicy, r); + ok(a.status === 200 && a.daten?.rolle === r, + `Spicy Media stellt auf "${r}" um (HTTP ${a.status})`); + } + const zurueck = await zu(keksSpicy, "creator"); + ok(zurueck.status === 200, `und wieder zurueck auf Creator (HTTP ${zurueck.status})`); + + /* DIE EINZIGE, DIE NICHT GEHT. */ + const hoch = await zu(keksSpicy, "admin"); + ok(hoch.status === 403, + `DogFather laesst sich nicht vergeben (HTTP ${hoch.status}, ${hoch.daten?.fehler || ""})`); + + /* AUCH NICHT VON DOGFATHER SELBST. Das ist der Satz "das ist die + einzige die man nicht auswaehlen kann" -- ohne Ausnahme. */ + const vonDogi = await zu(keksDogi, "admin"); + ok(vonDogi.status === 403, + `auch DogFather kann sie nicht vergeben (HTTP ${vonDogi.status})`); + + /* UND AN DOGFATHER SELBST AENDERT SIE NICHTS. Die Pruefungen oben + sehen auf die ZIEL-Rolle; dass die BETROFFENE Person DogFather + ist, faellt dort gar nicht auf. */ + const anDogi = await zu(keksSpicy, "manager", idDogi); + ok(anDogi.status === 403, + `an DogFathers Zeile aendert sie nichts (HTTP ${anDogi.status})`); + const dogiNoch = await ruf("GET", "/workspace/api/verwaltung/personen", keksDogi); + const istNoch = (dogiNoch.daten?.personen || []) + .find((x) => x.id === idDogi)?.rolle; + ok(istNoch === "admin", `und er ist immer noch DogFather (${istNoch})`); + + /* GEGENPROBE ZUR TUER: Ein Manager kommt an diesen Weg gar nicht -- + sonst hiesse "Spicy Media darf" nur, dass jeder darf. */ + const vonMax = await zu(keksMax, "scout"); + ok(vonMax.status === 404, `ein Manager kommt an diesen Weg nicht (HTTP ${vonMax.status})`); + + /* UND DIE UEBRIGE VERWALTUNG BLEIBT ZU. Die Tuer war eng gebaut; + diese Zeile ist der Beweis, dass sie eng geblieben ist. */ + const wegDamit = await ruf("DELETE", + `/workspace/api/verwaltung/personen/${idWechsel}`, keksSpicy); + ok(wegDamit.status === 404, + `loeschen geht fuer sie weiterhin nicht (HTTP ${wegDamit.status})`); +} { /* GEGENPROBE: Ein Manager kann KEINEN Manager anlegen -- sonst waere die zweite Tuer nur Zierde. */ @@ -549,6 +621,49 @@ console.log("\n=== Die Anmeldeseite ==="); `bei ihr steht der Abschnitt DogFather (${alsText.slice(0, 70) || "keine Abschnitte"})`); ok(/Manager|Creator|Scout/.test(alsText), "und die uebrigen Abschnitte ebenfalls -- die Liste ist nicht leer"); + + /* ERST AUFKLAPPEN, DANN MESSEN (11.09.2026). + + Die Kategorien stehen zugeklappt da, und `zeile(p)` -- die Funktion, + die die Knoepfe baut -- laeuft nur fuer eine OFFENE Kategorie. Der + erste Entwurf las sofort nach dem Laden und meldete "kein Knopf". + Das war kein Befund, das war eine zu frueh gestellte Frage; genau + derselbe Fehler wie heute frueh bei den Kacheln der Startseite. + + Geoeffnet wird die Kategorie, die es bei beiden Rollen gibt. */ + for (const kopf of await seite.$$(".gruppe__kopf")) { + const t = (await kopf.textContent()) || ""; + if (/Creator/.test(t)) { await kopf.click(); break; } + } + await seite.waitForTimeout(600); + const zeilenSpicy = await seite.$$eval(".person", (z) => z.length); + ok(zeilenSpicy > 0, `eine Kategorie ist aufgeklappt (${zeilenSpicy} Zeilen)`); + + /* ---- DER KNOPF, NICHT NUR DAS RECHT (11.09.2026) ---------------- + Am selben Tag ist mir im Chat genau das passiert: Das Recht war + richtig vergeben, die Oberflaeche wusste nichts davon, und der + Knopf blieb unsichtbar. Eine Pruefung, die nur die Schnittstelle + misst, waere dabei gruen geblieben. + + ZWEI AUSSAGEN, NICHT EINE: Der Knopf "Rolle aendern" muss da sein, + "Loeschen" NICHT -- das gehoert weiterhin DogFather. Vorher hingen + beide an derselben Zeile. */ + const knoepfeSpicy = await seite.$$eval(".person__tu, .tu-knopf, button", + (b) => b.map((x) => x.textContent.trim())); + ok(knoepfeSpicy.some((t) => /Rolle ändern/.test(t)), + `Spicy Media sieht "Rolle ändern" (${knoepfeSpicy.filter((t) => /Rolle|Löschen/.test(t)).join(", ") || "nichts davon"})`); + ok(!knoepfeSpicy.some((t) => /^Löschen$/.test(t)), + "und \"Löschen\" NICHT -- das bleibt bei DogFather"); + + /* Und in der Auswahl steht DogFather nicht. Gemessen an den + Knoepfen, die wirklich gebaut werden -- nicht an der Liste im + Quelltext, aus der sie entstehen. */ + const rollenKnoepfe = await seite.$$eval("#f-rolle .rollenwahl__knopf", + (b) => b.map((x) => x.dataset.rolle)); + ok(rollenKnoepfe.length >= 3 && !rollenKnoepfe.includes("admin"), + `zur Auswahl stehen ${rollenKnoepfe.join(", ")} -- ohne DogFather`); + ok(rollenKnoepfe.includes("spicy"), + "ihre eigene Rolle ist dabei -- Filipes Liste nennt sie ausdruecklich"); await ctx.close(); /* GEGENPROBE BEI DOGFATHER: Bei ihm steht der Abschnitt "Spicy Media" @@ -568,6 +683,28 @@ console.log("\n=== Die Anmeldeseite ==="); ok(/Spicy Media/.test(abschnitteDogi), `bei DogFather steht der Abschnitt "Spicy Media" (${abschnitteDogi.slice(0, 80)})`); ok(/DogFather/.test(abschnitteDogi), "und seiner ebenfalls"); + + for (const kopf of await seite2.$$(".gruppe__kopf")) { + const t = (await kopf.textContent()) || ""; + if (/Creator/.test(t)) { await kopf.click(); break; } + } + await seite2.waitForTimeout(600); + const zeilenDogi = await seite2.$$eval(".person", (z) => z.length); + ok(zeilenDogi > 0, `auch bei ihm ist sie aufgeklappt (${zeilenDogi} Zeilen)`); + + /* GEGENPROBE BEI DOGFATHER: Bei ihm steht "Loeschen" sehr wohl -- + sonst hiesse die Zeile oben nur, dass es den Knopf nirgends gibt. + Und auch in SEINER Auswahl fehlt DogFather. */ + const knoepfeDogi = await seite2.$$eval(".person__tu, .tu-knopf, button", + (b) => b.map((x) => x.textContent.trim())); + ok(knoepfeDogi.some((t) => /^Löschen$/.test(t)), + "bei DogFather steht \"Löschen\" da"); + ok(knoepfeDogi.some((t) => /Rolle ändern/.test(t)), + "und \"Rolle ändern\" ebenfalls"); + const rollenDogi = await seite2.$$eval("#f-rolle .rollenwahl__knopf", + (b) => b.map((x) => x.dataset.rolle)); + ok(rollenDogi.length >= 3 && !rollenDogi.includes("admin"), + `auch bei ihm ohne DogFather (${rollenDogi.join(", ")})`); await ctx2.close(); await browser.close(); } diff --git a/server/workspace-personen.js b/server/workspace-personen.js index eb1424d2..814f2aee 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, siehtModis, 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, darfRollenWechseln, hausBedingung, } from "./workspace.js"; import { sicherungJetzt } from "./workspace-sicherung.js"; @@ -100,6 +100,35 @@ function nurAdmin(req, res, next) { return next(); } + /* SPICY MEDIA DARF ROLLEN WECHSELN (11.09.2026). + + Filipe: "ich will dass die rolle spicy und dogfather, auch die + rollen wechseln koennen wenn die personen schon drin sind. von + alle kategorien, creator, scouts, manager spicy." + + DRITTE AUSNAHME, GLEICHE BAUWEISE wie die beiden darueber: eine + Methode, eine Adresse, eine Rolle. Wer hier etwas anderes baut, + hat drei Fassungen derselben Ausnahme -- und die dritte laesst + irgendwann mehr durch als gedacht. + + Codes, Sperren, Loeschen, Zuteilung und Protokoll bleiben bei + DogFather. Filipe hat das Rollenwechseln genannt, nicht die + Verwaltung. + + DER PFAD TRAEGT EINE NUMMER, laesst sich also nicht wie oben + vergleichen. Das Muster ist absichtlich streng: genau + /personen//rolle, nichts davor und nichts danach. + + WELCHE Rolle sie vergeben darf, steht NICHT hier -- das entscheidet + ANLEGBAR in der Route. Diese Zeile oeffnet nur die Tuer. */ + const rollenWeg = req.method === "PUT" + && /^\/workspace\/api\/verwaltung\/personen\/[0-9]+\/rolle$/ + .test(req.baseUrl + req.path); + if (darfRollenWechseln(person) && rollenWeg) { + req.person = person; + return next(); + } + if (!istDogFather(person)) return res.status(404).json({ fehler: "nicht_gefunden" }); req.person = person; next(); @@ -817,6 +846,29 @@ personenRouter.put("/workspace/api/verwaltung/personen/:id/rolle", gleicheHerkun return res.status(400).json({ fehler: "Diese Rolle hat sie schon." }); } + /* SICHERUNG 6 -- NEU AM 11.09.2026, WEIL SICH DIE TUER GEOEFFNET HAT. + + Seit Spicy Media Rollen wechseln darf, gibt es einen Fall, den + es vorher nicht geben konnte: jemand ohne DogFather-Rolle, der + an einer DogFather-Zeile steht. + + DIE PRUEFUNGEN DARUEBER FANGEN DAS NICHT. Sie sehen auf die + ZIEL-Rolle ("darfst du 'manager' vergeben?") -- und 'manager' + darf Spicy Media vergeben. Dass die Person, die da herabgestuft + wird, DogFather ist, steht in der AUSGANGS-Rolle, und die kam + bis heute nirgends vor. + + Sicherung 3 (nie den letzten DogFather) haette es heute + zufaellig abgefangen, weil es genau einen gibt. Eine Sperre, + die nur wegen einer Zahl im Bestand haelt, ist keine. + + Zusaetzlich sieht Spicy Media DogFather gar nicht in der Liste + (`req.ohneDogFather`). Das ist eine Sicht, keine Schranke -- wer + die Nummer kennt, ruft den Weg direkt auf. */ + if (person.rolle === "admin" && !istDogFather(req.person)) { + return res.status(403).json({ fehler: "An der DogFather-Rolle ändert nur DogFather." }); + } + /* SICHERUNG 2 */ if (id === req.person.id) { return res.status(400).json({ fehler: "Die eigene Rolle lässt sich nicht ändern.", diff --git a/server/workspace.js b/server/workspace.js index 32b00ecb..5aa6e181 100644 --- a/server/workspace.js +++ b/server/workspace.js @@ -219,10 +219,35 @@ export const istDogFather = (person) => !!person && person.rolle === "admin"; endgueltigen Rechten, und den vergibt nur DogFather selbst. ======================================================================= */ const ANLEGBAR = { - /* DogFather: alles, was es gibt. Er geht ueber /verwaltung/personen. */ - admin: [...ROLLEN], - /* Spicy Media: das ganze Team, aber keine Leitung ueber sich. */ - spicy: ["manager", "scout", "creator"], + /* DogFather: alles ausser der eigenen Rolle. + + DIE ROLLE "admin" IST SEIT DEM 11.09.2026 NICHT MEHR VERGEBBAR -- + von niemandem, auch nicht von DogFather selbst. Filipe: "dogfather + soll man nicht auswaehlen koennen. das ist die einzige die man + nicht auswaehlen kann bitte." + + WAS DAS BEDEUTET, damit es niemand spaeter sucht: Es laesst sich + kein zweiter DogFather-Zugang mehr anlegen, und niemand laesst + sich zu einem befoerdern. Der bestehende bleibt unberuehrt und ist + durch Sicherung 3 (nie den letzten DogFather herabstufen) + geschuetzt -- er kann also nicht versehentlich verschwinden. + Zurueckdrehen laesst sich das nur hier in dieser Liste. + + Nebenwirkung, und sie ist erwuenscht: Damit gibt es keinen Weg + mehr, sich ueber die Oberflaeche zur hoechsten Rolle zu machen. */ + admin: [...ROLLEN].filter((r) => r !== "admin"), + /* Spicy Media: das ganze Team -- und seit dem 11.09.2026 auch die + eigene Rolle. + + Filipe: "ich will dass die rolle spicy und dogfather, auch die + rollen wechseln koennen wenn die personen schon drin sind. von + alle kategorien, creator, scouts, manager spicy." + + Dass jemand seine eigene Rolle weitergeben kann, ist eine + Entscheidung und kein Versehen: Spicy Media fuehrt die Agentur. + DogFather bleibt trotzdem ausserhalb der Liste -- niemand hebt + sich ueber die Rolle, die ihn eingesetzt hat. */ + spicy: ["spicy", "manager", "scout", "creator"], /* Ein Manager stellt Creator ein, die er dann auch betreut. */ manager: ["creator"], }; @@ -247,6 +272,26 @@ export function darfAnlegen(person) { return alle.filter((r) => HAUS_TEAM_ROLLEN.has(r)); } +/** Wer darf die Rolle einer Person aendern, die schon da ist? + * + * (11.09.2026) Filipe: "ich will dass die rolle spicy und dogfather, + * auch die rollen wechseln koennen wenn die personen schon drin + * sind." + * + * EINE REGEL, DREI BENUTZER: die Schranke in nurAdmin, der Knopf in + * der Oberflaeche (ueber `darf_rollen_wechseln` in /api/ich) und die + * Route selbst. Stuende sie dreimal da, waere die dritte Abschrift + * die, die eine Rolle vergisst -- genau so ist am selben Tag im Chat + * ein Knopf unsichtbar geblieben, obwohl das Recht stimmte. + * + * WAS SIE NICHT ENTSCHEIDET: WELCHE Rolle vergeben werden darf. Das + * steht in ANLEGBAR und ist bewusst getrennt -- "darf ueberhaupt + * wechseln" und "darf DIESE Rolle vergeben" sind zwei Fragen, und + * ihre Antworten laufen auseinander, sobald eine Rolle dazukommt. + */ +export const darfRollenWechseln = (person) => + !!person && (person.rolle === "admin" || person.rolle === "spicy"); + /* WER FUEHRT TEAM DOGI? (10.09.2026) * * DogFather und seine rechte Hand -- und sonst niemand. Spicy Media und @@ -3982,6 +4027,12 @@ workspaceRouter.get("/workspace/api/ich", (req, res) => { serverseitig offen war. Wer die Antwort nur an einer Stelle hat, kann sie nicht an zweien verschieden haben. */ darf_anlegen: darfAnlegen(person), + /* OB DER KNOPF "ROLLE AENDERN" ERSCHEINT (11.09.2026). Aus + derselben Regel wie die Schranke dahinter -- die Oberflaeche + vergleicht keine Rollennamen mehr selbst. Vorher stand dort + `ich.rolle === 'admin'`, und dieselbe Zeile schaltete auch das + Loeschen frei; die beiden gehoeren nicht zusammen. */ + darf_rollen_wechseln: darfRollenWechseln(person), /* DIE KACHELN, WENN SIE NICHT IM BROWSER STEHEN DUERFEN. Fuer die fuenf bekannten Rollen steht hier `null`, und die diff --git a/workspace/app.webmanifest b/workspace/app.webmanifest index c03beffe..c628b369 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=202609112358", + "src": "/assets/img/app-symbole/workspace-192.png?v=202609120025", "sizes": "192x192", "type": "image/png", "purpose": "any" }, { - "src": "/assets/img/app-symbole/workspace-512.png?v=202609112358", + "src": "/assets/img/app-symbole/workspace-512.png?v=202609120025", "sizes": "512x512", "type": "image/png", "purpose": "any" }, { - "src": "/assets/img/app-symbole/workspace-192-maskable.png?v=202609112358", + "src": "/assets/img/app-symbole/workspace-192-maskable.png?v=202609120025", "sizes": "192x192", "type": "image/png", "purpose": "maskable" }, { - "src": "/assets/img/app-symbole/workspace-512-maskable.png?v=202609112358", + "src": "/assets/img/app-symbole/workspace-512-maskable.png?v=202609120025", "sizes": "512x512", "type": "image/png", "purpose": "maskable" diff --git a/workspace/assets/css/personen.css b/workspace/assets/css/personen.css index 45bc8d62..453712b2 100644 --- a/workspace/assets/css/personen.css +++ b/workspace/assets/css/personen.css @@ -390,7 +390,11 @@ body[data-nur-anlegen="ja"] #rest-schalter { display: none; } nichts tun -- die Sperre steht im Server. Diese Unterscheidung steht hier ausdruecklich, weil sie beim naechsten Umbau leicht verrutscht. */ body[data-nur-lesen="ja"] #liste { display: block; } -body[data-nur-lesen="ja"] .person__knoepfe, +/* `.person__knoepfe` stand hier bis zum 11.09.2026 mit drin. Seit + Spicy Media Rollen wechseln darf, hat sie GENAU EINEN Knopf -- und + eine Regel, die die ganze Reihe ausblendet, haette ihn mit + weggenommen. Welche Knoepfe entstehen, entscheidet jetzt + personen.js; was es nicht gibt, muss man auch nicht verstecken. */ body[data-nur-lesen="ja"] .person__code, body[data-nur-lesen="ja"] .zuteilung, body[data-nur-lesen="ja"] select { display: none; } diff --git a/workspace/assets/js/personen.js b/workspace/assets/js/personen.js index 5df8beee..66358b5b 100644 --- a/workspace/assets/js/personen.js +++ b/workspace/assets/js/personen.js @@ -31,8 +31,21 @@ const ROLLEN = [ { wert: 'spicy', name: 'Spicy Media', symbol: 'chili', text: 'Überblick über alle – ohne Automationen, ohne fremde Chats. Legt Leute an.' }, + /* DER EINTRAG BLEIBT, DER KNOPF ERSCHEINT NICHT (11.09.2026). + + Seit `ANLEGBAR` die Rolle `admin` nicht mehr enthaelt, filtert + die Zeile unten (`darf.includes(...)`) ihn von selbst heraus -- + fuer jeden, auch fuer DogFather. Filipe: "dogfather soll man + nicht auswaehlen koennen. das ist die einzige die man nicht + auswaehlen kann bitte." + + Warum er trotzdem hier steht: Diese Liste ist auch das + Nachschlagewerk fuer Name und Zeichen der Rolle. Ihn zu loeschen + hiesse, an anderer Stelle eine zweite Liste zu brauchen. Der + Text sagt jetzt, was gilt -- ein Text, der etwas anderes + verspricht als die Oberflaeche tut, ist schlimmer als keiner. */ { wert: 'admin', name: 'DogFather', symbol: 'husky', - text: 'Alle Rechte, endgültig. Nur DogFather legt DogFather, Spicy Media und Manager an.' }, + text: 'Alle Rechte, endgültig. Diese Rolle lässt sich nicht vergeben – auch nicht von DogFather.' }, /* Der Satz stimmte bis zum 07.09.2026 -- seither legen Manager Creator an, und ein Text, der etwas anderes verspricht als die Oberflaeche tut, ist schlimmer als gar keiner. */ @@ -495,6 +508,27 @@ schlimmer als kein Knopf. */ if (ich.rolle === 'hand') { k.append(links, knoepfe); return k; } + /* WER NICHT DOGFATHER IST, BEKOMMT NUR, WAS ER DARF (11.09.2026). + + Vorher war das eine Ja/Nein-Frage: DogFather bekam alles, alle + anderen nichts (bei Spicy Media blendete zusaetzlich das CSS die + ganze Reihe aus). Seit Filipes Wunsch -- "ich will dass die rolle + spicy und dogfather, auch die rollen wechseln koennen wenn die + personen schon drin sind" -- gibt es einen Zwischenfall: eine + Rolle mit GENAU EINEM Knopf. + + Die Verzweigung hier statt einer CSS-Regel: Ein Knopf, den es + gar nicht gibt, kann auch nicht durch eine spaetere Stilaenderung + wieder auftauchen. Und "Neuer Code" und "Sperren" wuerden ihr + weiterhin 404 bringen -- die bleiben deshalb aus. */ + if (ich.rolle !== 'admin') { + if (ich.darf_rollen_wechseln && p.rolle !== 'admin') { + knoepfe.append(tuKnopf('Rolle ändern', () => rolleFragen(p))); + } + k.append(links, knoepfe); + return k; + } + knoepfe.append(tuKnopf('Neuer Code', async () => { const eigen = p.id === ich.id; const frage = eigen @@ -539,13 +573,29 @@ zuerst. Bis heute war Löschen und Neuanlegen der einzige Weg, jemandem eine andere Aufgabe zu geben; genau das soll dieser Knopf ersparen. */ - if (ich.rolle === 'admin') { - knoepfe.append(tuKnopf('Rolle ändern', () => rolleFragen(p))); + /* ZWEI KNOEPFE, ZWEI BEDINGUNGEN (11.09.2026). - const weg = tuKnopf('Löschen', () => loeschenFragen(p)); - weg.dataset.gefahr = 'ja'; - knoepfe.append(weg); - } + Hier stand EINE Zeile (`ich.rolle === 'admin'`) fuer beide. + Filipe: "ich will dass die rolle spicy und dogfather, auch die + rollen wechseln koennen wenn die personen schon drin sind." + Loeschen bleibt bei DogFather -- das hat er nicht genannt, und + "Nur DogFather hat alle endgueltigen Rechte" gilt weiter. + + Die Antwort kommt vom Server (`darf_rollen_wechseln`), nicht + aus einem Rollenvergleich hier. Am selben Tag hat mich genau + das im Chat eine Stunde gekostet: zwei Stellen, eine Aussage, + und nur eine wusste Bescheid. + + An DogFather selbst aendert nur DogFather -- Spicy Media sieht + seine Zeile ohnehin nicht, aber ein Knopf, der eine Absage + bringt, gehoert auch dann nicht hin. */ + /* Ab hier ist `ich` DogFather -- die Verzweigung weiter oben hat + alle anderen schon verabschiedet. Beide Knoepfe gehoeren ihm. */ + knoepfe.append(tuKnopf('Rolle ändern', () => rolleFragen(p))); + + const weg = tuKnopf('Löschen', () => loeschenFragen(p)); + weg.dataset.gefahr = 'ja'; + knoepfe.append(weg); } k.append(links, knoepfe); diff --git a/workspace/aufgaben.html b/workspace/aufgaben.html index c5a93202..2fc9a68d 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 @@ - - - - - + + + + + diff --git a/workspace/automation.html b/workspace/automation.html index f2157910..a9d1f8b8 100644 --- a/workspace/automation.html +++ b/workspace/automation.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -147,10 +147,10 @@ - - - - - + + + + + diff --git a/workspace/bereich.html b/workspace/bereich.html index b5207725..6d6ad805 100644 --- a/workspace/bereich.html +++ b/workspace/bereich.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -181,14 +181,14 @@ - - - - - - - - - + + + + + + + + + diff --git a/workspace/calls.html b/workspace/calls.html index 6c96e98d..adca2a19 100644 --- a/workspace/calls.html +++ b/workspace/calls.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -89,11 +89,11 @@ - - - - - - + + + + + + diff --git a/workspace/chat.html b/workspace/chat.html index 91512b4c..8ac66e22 100644 --- a/workspace/chat.html +++ b/workspace/chat.html @@ -12,26 +12,26 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - + + + + - - - + + + - + @@ -341,10 +341,10 @@ - - - - - + + + + + diff --git a/workspace/content.html b/workspace/content.html index 3f0889cd..04e615b8 100644 --- a/workspace/content.html +++ b/workspace/content.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -179,12 +179,12 @@ - - - - - - - + + + + + + + diff --git a/workspace/crew-index.html b/workspace/crew-index.html index 5c224300..09254be4 100644 --- a/workspace/crew-index.html +++ b/workspace/crew-index.html @@ -36,15 +36,15 @@ - - - + + + - + @@ -319,6 +319,6 @@ - + diff --git a/workspace/crew.webmanifest b/workspace/crew.webmanifest index 7e9f949b..7f256f08 100644 --- a/workspace/crew.webmanifest +++ b/workspace/crew.webmanifest @@ -13,25 +13,25 @@ "theme_color": "#06090f", "icons": [ { - "src": "/assets/img/app-symbole/crew-192.png?v=202609112358", + "src": "/assets/img/app-symbole/crew-192.png?v=202609120025", "sizes": "192x192", "type": "image/png", "purpose": "any" }, { - "src": "/assets/img/app-symbole/crew-512.png?v=202609112358", + "src": "/assets/img/app-symbole/crew-512.png?v=202609120025", "sizes": "512x512", "type": "image/png", "purpose": "any" }, { - "src": "/assets/img/app-symbole/crew-192-maskable.png?v=202609112358", + "src": "/assets/img/app-symbole/crew-192-maskable.png?v=202609120025", "sizes": "192x192", "type": "image/png", "purpose": "maskable" }, { - "src": "/assets/img/app-symbole/crew-512-maskable.png?v=202609112358", + "src": "/assets/img/app-symbole/crew-512-maskable.png?v=202609120025", "sizes": "512x512", "type": "image/png", "purpose": "maskable" diff --git a/workspace/dateien.html b/workspace/dateien.html index b6e7a06a..06bf8c72 100644 --- a/workspace/dateien.html +++ b/workspace/dateien.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -108,10 +108,10 @@ - - - - - + + + + + diff --git a/workspace/entwicklung.html b/workspace/entwicklung.html index 99837ba4..4719b819 100644 --- a/workspace/entwicklung.html +++ b/workspace/entwicklung.html @@ -7,14 +7,14 @@ - - - - - - - - + + + + + + + + @@ -94,9 +94,9 @@ - - - - + + + + diff --git a/workspace/index.html b/workspace/index.html index 7cea47e5..babf3f52 100644 --- a/workspace/index.html +++ b/workspace/index.html @@ -30,9 +30,9 @@ - - - + + + @@ -401,6 +401,6 @@ - + diff --git a/workspace/kalender.html b/workspace/kalender.html index 2f6934ca..e6ead905 100644 --- a/workspace/kalender.html +++ b/workspace/kalender.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -377,11 +377,11 @@ - - - - - - + + + + + + diff --git a/workspace/leistung.html b/workspace/leistung.html index c627e718..de1a8448 100644 --- a/workspace/leistung.html +++ b/workspace/leistung.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -382,10 +382,10 @@ - - - - - + + + + + diff --git a/workspace/personen.html b/workspace/personen.html index 9d36c717..ffc6d345 100644 --- a/workspace/personen.html +++ b/workspace/personen.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -423,10 +423,10 @@ - - - - - + + + + + diff --git a/workspace/profil.html b/workspace/profil.html index db4d644a..7c650533 100644 --- a/workspace/profil.html +++ b/workspace/profil.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -214,11 +214,11 @@ - - - - - - + + + + + + diff --git a/workspace/rechte.html b/workspace/rechte.html index c2f95584..87c9ad03 100644 --- a/workspace/rechte.html +++ b/workspace/rechte.html @@ -7,14 +7,14 @@ - - - - - - - - + + + + + + + + @@ -134,9 +134,9 @@ Beim ersten Anlauf fehlte die Zeile auf genau diesen beiden neuen Seiten. Gefunden hat das nicht das Auge, sondern pruef-css-klassen, die seit dem 07.09. jede Seite danach absucht. --> - - - - + + + + diff --git a/workspace/report.html b/workspace/report.html index a53dffab..5cbe10d7 100644 --- a/workspace/report.html +++ b/workspace/report.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -106,11 +106,11 @@ - - - - - - + + + + + + diff --git a/workspace/scouting.html b/workspace/scouting.html index 4c6200e4..03c00e4f 100644 --- a/workspace/scouting.html +++ b/workspace/scouting.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -173,10 +173,10 @@ - - - - - + + + + + diff --git a/workspace/start.html b/workspace/start.html index e1732782..69791afb 100644 --- a/workspace/start.html +++ b/workspace/start.html @@ -12,21 +12,21 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - + + + + - - + + - + @@ -674,10 +674,10 @@

- - - - - + + + + + diff --git a/workspace/startcheck.html b/workspace/startcheck.html index afcea918..c57bb304 100644 --- a/workspace/startcheck.html +++ b/workspace/startcheck.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -85,11 +85,11 @@ - - - - - - + + + + + + diff --git a/workspace/steckbrief.html b/workspace/steckbrief.html index 9261a5c1..594331c6 100644 --- a/workspace/steckbrief.html +++ b/workspace/steckbrief.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -126,10 +126,10 @@ - - - - - + + + + + diff --git a/workspace/talente.html b/workspace/talente.html index 05addbda..19348026 100644 --- a/workspace/talente.html +++ b/workspace/talente.html @@ -7,14 +7,14 @@ - - - - - - - - + + + + + + + + @@ -94,9 +94,9 @@ - - - - + + + + diff --git a/workspace/team.html b/workspace/team.html index f2f3a20b..09dbbc3e 100644 --- a/workspace/team.html +++ b/workspace/team.html @@ -7,20 +7,20 @@ - - - - - - - + + + + + + + - + @@ -110,10 +110,10 @@ - - - - - + + + + + diff --git a/workspace/teamlage.html b/workspace/teamlage.html index 3cfa96c8..34a65d66 100644 --- a/workspace/teamlage.html +++ b/workspace/teamlage.html @@ -7,20 +7,20 @@ - - - - - - - + + + + + + + - + - - - - + + + + diff --git a/workspace/treff-moderation.html b/workspace/treff-moderation.html index e5dac67e..3fcab583 100644 --- a/workspace/treff-moderation.html +++ b/workspace/treff-moderation.html @@ -7,14 +7,14 @@ - - - - - - - - + + + + + + + + @@ -110,9 +110,9 @@ - - - - + + + + diff --git a/workspace/treff-regeln.html b/workspace/treff-regeln.html index 71b2091d..ae891cda 100644 --- a/workspace/treff-regeln.html +++ b/workspace/treff-regeln.html @@ -7,18 +7,18 @@ - - - - - - - + + + + + + + - + @@ -190,9 +190,9 @@ Beim ersten Anlauf fehlte die Zeile auf genau diesen beiden neuen Seiten. Gefunden hat das nicht das Auge, sondern pruef-css-klassen, die seit dem 07.09. jede Seite danach absucht. --> - - - - + + + + diff --git a/workspace/uebersicht.html b/workspace/uebersicht.html index 9c1d1a2e..094071a0 100644 --- a/workspace/uebersicht.html +++ b/workspace/uebersicht.html @@ -12,22 +12,22 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - + + + + - - - + + + - + @@ -149,11 +149,11 @@ - + - - - - + + + + diff --git a/workspace/wissen.html b/workspace/wissen.html index 693ade55..3889e10f 100644 --- a/workspace/wissen.html +++ b/workspace/wissen.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -190,10 +190,10 @@ - - - - - + + + + +