Manager legen Creator an -- eine neue Tuer statt eines Schluessels fuer die alte
Filipe: "wieso greift das in die rechte rein? ist doch ok, die sollen einfach paar leute selber hinzufuegen koennen." Er hat recht, und ich hatte zwei Dinge in einen Topf geworfen: Das hier braucht KEINE Datenbankaenderung -- nur die Rolle "Spicy Media" braucht eine. WARUM EIN EIGENER WEG UND NICHT DIE ALTE TUER Alles unter /workspace/api/verwaltung haengt an EINER Schranke (nurAdmin). Dahinter liegen acht Wege: Rollen aendern, Codes neu setzen, sperren, loeschen, Protokoll lesen. Einen Manager dort hineinzulassen und danach in jedem der acht einzeln zu pruefen, was er darf, ist genau die Bauweise, durch die am 31.08.2026 ein Loch entstanden ist -- zwei von drei Stellen abgesichert, die dritte vergessen. Deshalb bleibt die Tuer zu, und daneben steht eine neue mit genau einem Zweck: POST /workspace/api/creator-anlegen. Sie kann nichts anderes, als einen Creator anzulegen -- nicht weil eine Abfrage es verbietet, sondern weil es hier keinen anderen Weg gibt. Unterschied zwischen "darf nicht" und "kann nicht". DIE ROLLE STEHT NICHT IM AUFRUF, sie wird im Server gesetzt. Ein Feld `rolle` im Koerper waere die naheliegende Loesung und die falsche: Dann muesste eine Abfrage sie pruefen, und eine vergessene Abfrage ist ein zweiter Zugang mit vollen Rechten. Geprueft wird deshalb nicht, dass ein mitgeschicktes `rolle: "admin"` abgelehnt wird, sondern dass es WIRKUNGSLOS ist. DIE ZUTEILUNG PASSIERT SOFORT. Ein Creator ohne Betreuung ist fuer alle ausser DogFather unsichtbar -- der Manager haette ihn angelegt und danach nicht mehr gesehen. Wer anlegt, betreut; ein eigener Scout kann mitgegeben werden. Eine FREMDE Scout-Nummer wird abgelehnt (403) und nicht stillschweigend auf den Anleger zurueckgesetzt: Sonst glaubte der Manager, er haette zugeteilt. Der Knopf sitzt auf dem Dashboard, nicht in der Personenverwaltung -- dort kommt ein Manager gar nicht hinein, und hier sieht er seine Creator ohnehin. Der Zugangscode steht einmal im Dialog und wird nie nachgeladen; deshalb schliesst sich das Fenster NICHT von selbst. pruef-creator-anlegen.mjs, 29 Pruefungen, alle gruen -- und die Haelfte davon prueft, was NICHT geht: Personenverwaltung 404 fuer Manager, Scout und Creator kommen gar nicht erst durch, fremder Scout 403 (und der Creator wird dabei gar nicht erst angelegt), erfundene Nummer 403. Zwei Manager mit je einem eigenen Scout, weil sich "nur die eigenen" mit nur einem Manager gar nicht pruefen laesst. Nebenbei: .feld-hinweis ist von bereich.css nach aufgaben.css gewandert (zu den uebrigen Formularstilen) -- ein Formularbaustein in der Bereichsdatei ist nur so lange richtig, wie ihn keine zweite Seite braucht. Gruen: creator-anlegen (29), personen-liste (33), css-klassen (15), struktur (32), formulare (19). Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
@@ -275,6 +275,117 @@ personenRouter.put("/workspace/api/verwaltung/scout-zuteilung/:id", gleicheHerku
|
||||
}
|
||||
});
|
||||
|
||||
/* =======================================================================
|
||||
EIN MANAGER LEGT EINEN CREATOR AN (07.09.2026)
|
||||
|
||||
Wunsch Filipe: "ich will auch dass manager ab jetzt creator und auch
|
||||
wirklich nur creator hinzufuegen koennen auf die seite. die creator
|
||||
sollen ... auch nur der person hinzugefuegt werden wo dan diesen
|
||||
creator hinzufuegt oder den scouts von diesem manager."
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
WARUM DAS EIN EIGENER WEG IST UND NICHT DIE ALTE TUER
|
||||
|
||||
Alles unter `/workspace/api/verwaltung` haengt an EINER Schranke:
|
||||
`nurAdmin`. Dahinter liegen acht Wege -- Rollen aendern, Codes neu
|
||||
setzen, sperren, loeschen, das Protokoll lesen. Einen Manager dort
|
||||
hineinzulassen und danach in jedem der acht Wege einzeln zu pruefen,
|
||||
was er darf, ist genau die Bauweise, durch die am 31.08.2026 schon
|
||||
einmal ein Loch entstanden ist: Zwei von drei Stellen waren
|
||||
abgesichert, die dritte vergessen.
|
||||
|
||||
Deshalb bleibt die Tuer zu, und daneben steht eine neue mit genau
|
||||
EINEM Zweck. Sie kann nichts anderes, als einen Creator anzulegen --
|
||||
nicht weil eine Abfrage es verbietet, sondern weil es hier gar keinen
|
||||
anderen Weg gibt. Das ist der Unterschied zwischen "darf nicht" und
|
||||
"kann nicht".
|
||||
|
||||
DIE ROLLE STEHT NICHT IM AUFRUF. Sie wird hier gesetzt. Ein Feld
|
||||
`rolle` im Koerper waere die naheliegende Loesung und die falsche:
|
||||
Dann muesste eine Abfrage sie pruefen, und eine vergessene Abfrage
|
||||
ist ein zweiter Zugang mit vollen Rechten.
|
||||
|
||||
DIE ZUTEILUNG PASSIERT SOFORT UND HIER. Ein Creator ohne Betreuung
|
||||
ist fuer alle ausser DogFather unsichtbar -- der Manager haette ihn
|
||||
angelegt und danach nicht mehr gesehen. Wer anlegt, betreut; ein Scout
|
||||
des Managers kann gleich mitgegeben werden ("oder den scouts von
|
||||
diesem manager").
|
||||
======================================================================= */
|
||||
function nurLeitung(req, res, next) {
|
||||
const person = sitzungLesen(req);
|
||||
if (!person) return res.status(401).json({ fehler: "nicht_angemeldet" });
|
||||
if (!istLeitung(person)) return res.status(404).json({ fehler: "nicht_gefunden" });
|
||||
req.person = person;
|
||||
next();
|
||||
}
|
||||
|
||||
personenRouter.post("/workspace/api/creator-anlegen", gleicheHerkunft, nurLeitung, (req, res) => {
|
||||
try {
|
||||
const name = String(req.body?.name ?? "").trim();
|
||||
if (name.length < 2) return res.status(400).json({ fehler: "Name fehlt." });
|
||||
if (name.length > NAME_MAX) return res.status(400).json({ fehler: "Name ist zu lang." });
|
||||
|
||||
const vorhanden = db().prepare(
|
||||
"SELECT 1 FROM personen WHERE lower(name) = lower(?) AND aktiv = 1").get(name);
|
||||
if (vorhanden) return res.status(409).json({ fehler: "Diesen Namen gibt es schon." });
|
||||
|
||||
/* Wem der neue Creator gehoert. Vorgabe: dem, der ihn anlegt.
|
||||
Ein Manager darf stattdessen einen SEINER Scouts angeben -- und
|
||||
nur einen seiner eigenen. Wer eine fremde Nummer hineinschreibt,
|
||||
bekommt sie nicht, sondern eine Absage: Stillschweigend auf die
|
||||
Vorgabe zurueckzufallen waere schlimmer, weil der Manager dann
|
||||
glaubt, er haette zugeteilt. */
|
||||
let betreuerId = req.person.id;
|
||||
const gewuenscht = req.body?.betreuer_id;
|
||||
if (gewuenscht !== undefined && gewuenscht !== null && gewuenscht !== "") {
|
||||
const z = Number(gewuenscht);
|
||||
if (!Number.isInteger(z) || z < 1) return res.status(400).json({ fehler: "Ungültige Zuordnung." });
|
||||
if (z !== req.person.id) {
|
||||
const erlaubt = istDogFather(req.person)
|
||||
? db().prepare("SELECT 1 FROM personen WHERE id = ? AND aktiv = 1 AND rolle IN ('admin','manager','scout')").get(z)
|
||||
: db().prepare(`SELECT 1 FROM personen p
|
||||
JOIN scout_zuteilung s ON s.scout_id = p.id
|
||||
WHERE p.id = ? AND p.aktiv = 1 AND p.rolle = 'scout'
|
||||
AND s.manager_id = ?`).get(z, req.person.id);
|
||||
if (!erlaubt) {
|
||||
return res.status(403).json({
|
||||
fehler: "Diesen Scout betreust du nicht – zuteilen kannst du nur deine eigenen.",
|
||||
});
|
||||
}
|
||||
}
|
||||
betreuerId = z;
|
||||
}
|
||||
|
||||
const neu = personAnlegen(name, "creator", { ...req.person, ip: echteIp(req) });
|
||||
betreuungSetzen(neu.id, betreuerId, { ...req.person, ip: echteIp(req) });
|
||||
|
||||
/* Der Code steht NUR hier in der Antwort. Danach ist er weg. */
|
||||
res.status(201).json({ id: neu.id, name: neu.name, rolle: neu.rolle, code: neu.code,
|
||||
betreuer_id: betreuerId });
|
||||
} catch (fehler) {
|
||||
console.error("[workspace] Creator anlegen:", fehler?.message);
|
||||
res.status(503).json({ fehler: "nicht_verfuegbar" });
|
||||
}
|
||||
});
|
||||
|
||||
/* Welche Scouts kann ich einem neuen Creator gleich mitgeben?
|
||||
Dieselbe Regel wie oben, nur lesend -- damit die Oberflaeche genau
|
||||
die Liste anbietet, die der Server auch annimmt. Zwei getrennte
|
||||
Listen waeren die naechste Stelle, an der beide auseinanderlaufen. */
|
||||
personenRouter.get("/workspace/api/creator-anlegen/scouts", nurLeitung, (req, res) => {
|
||||
try {
|
||||
const zeilen = istDogFather(req.person)
|
||||
? db().prepare("SELECT id, name FROM personen WHERE aktiv = 1 AND rolle = 'scout' ORDER BY name").all()
|
||||
: db().prepare(`SELECT p.id, p.name FROM personen p
|
||||
JOIN scout_zuteilung s ON s.scout_id = p.id
|
||||
WHERE p.aktiv = 1 AND p.rolle = 'scout' AND s.manager_id = ?
|
||||
ORDER BY p.name`).all(req.person.id);
|
||||
res.json({ scouts: zeilen });
|
||||
} catch {
|
||||
res.status(503).json({ fehler: "nicht_verfuegbar" });
|
||||
}
|
||||
});
|
||||
|
||||
/* ---------- Anlegen ----------------------------------------------------- */
|
||||
|
||||
personenRouter.post("/workspace/api/verwaltung/personen", gleicheHerkunft, (req, res) => {
|
||||
|
||||
Reference in New Issue
Block a user