diff --git a/server/pruef-verteilen.mjs b/server/pruef-verteilen.mjs index 78ac2d48..628022a5 100644 --- a/server/pruef-verteilen.mjs +++ b/server/pruef-verteilen.mjs @@ -160,14 +160,36 @@ const vonDogi = await anlegenFuer(kDogi, idModi2, "Von DogFather an Ghost"); ok(vonDogi.code === 201 && vonDogi.verant === idModi2, `DogFather ebenso (${vonDogi.code}, liegt bei ${vonDogi.verant})`); -/* DIE ENTSCHEIDENDE GEGENPROBE: Ein Modi versucht dasselbe. Die - Aufgabe wird NICHT abgelehnt -- sie landet bei ihm selbst. Das ist - freundlicher als ein Fehler und genau das, was Filipe wollte: - "jeder soll sich selber aufgabe vergeben koennen". */ +/* DIE ENTSCHEIDENDE GEGENPROBE: Ein Modi versucht dasselbe. + --------------------------------------------------------------------- + BIS ZUM 22.09.2026 stand hier, die Aufgabe lande bei ihm selbst -- + "jeder soll sich selber aufgabe vergeben koennen" (20.09.). Filipe + hat das ausdruecklich umgedreht: "damit wir endlich den modis + aufgaben anstaendig verteilen koennen und sie sich nicht selber + aufgaben geben." + + Im Team Dogi kommen Aufgaben jetzt von der Leitung. Ein Modi + bekommt 403 -- und das ist der Unterschied, auf den es ankommt: Er + kann sich keine geben, weder sich selbst noch jemand anderem. */ const vonModi = await anlegenFuer(kModi, idModi2, "Versuch eines Modi"); -ok(vonModi.code === 201 && vonModi.verant === idModi, - `Gegenprobe: ein Modi kann es versuchen — die Aufgabe landet bei ihm selbst ` - + `(${vonModi.verant}, nicht ${idModi2})`); +ok(vonModi.code === 403, + `Gegenprobe: ein Modi legt gar keine Aufgabe mehr an (${vonModi.code})`); + +/* UND IN DER AGENTUR BLEIBT ES, WIE ES WAR. Dort ist eine Aufgabe eine + Notiz an sich selbst, kein Auftrag von jemandem -- eine Regel, die + beide Haeuser ueber einen Kamm schert, waere falsch. */ +{ + const w = await import("./workspace.js"); + ok(w.darfAufgabenAnlegen({ rolle: "creator" }) === true + && w.darfAufgabenAnlegen({ rolle: "manager" }) === true, + "in der Agentur legt weiterhin jeder fuer sich selbst an"); + ok(w.darfAufgabenAnlegen({ rolle: "modi" }) === false, + "ein Modi nicht"); + ok(w.darfAufgabenAnlegen({ rolle: "hand" }) === true + && w.darfAufgabenAnlegen({ rolle: "linke" }) === true + && w.darfAufgabenAnlegen({ rolle: "admin" }) === true, + "die drei, die verteilen duerfen, schon"); +} /* ======================================================================= DIE FELDER MUESSEN AUCH ZU SEHEN SEIN diff --git a/server/pruef-zuteilung.mjs b/server/pruef-zuteilung.mjs index 0f97748b..00ce4396 100644 --- a/server/pruef-zuteilung.mjs +++ b/server/pruef-zuteilung.mjs @@ -359,15 +359,21 @@ melde("\n=== Eine einzelne Person ==="); ===================================================================== */ melde("\n=== Grenzen beim Verteilen ==="); { + /* EIN MODI LEGT GAR NICHTS MEHR AN (22.09.2026). + ------------------------------------------------------------------ + Hier stand bis heute: "Anna darf sich selbst etwas notieren" -- + ihre Zuteilung an Bea wurde stillschweigend auf sie selbst + umgebogen. Filipe hat das umgedreht: "sie sich nicht selber + aufgaben geben." + + 403 ist hier die ehrlichere Antwort als ein stilles Umbiegen: Wer + etwas versucht, das nicht vorgesehen ist, soll es erfahren -- und + nicht ein Ergebnis bekommen, das er nicht gemeint hat. */ const a = await rufe("/workspace/api/aufgaben", { method: "POST", keks: anna, body: { titel: "Bea soll das machen", zuteilung: [idBea] } }); - ok(a.code === 201, `Anna darf sich selbst etwas notieren (HTTP ${a.code})`); - const beiBea = await aufgabeBei(bea, a.json?.id); - ok(!beiBea?.meine_zuteilung, - "aber Bea bekommt nichts davon zugeteilt"); - const beiAnna = await aufgabeBei(anna, a.json?.id); - ok(beiAnna?.verantwortlich_name === "Anna", - `die Aufgabe liegt bei Anna selbst (${beiAnna?.verantwortlich_name})`); + ok(a.code === 403, `ein Modi legt gar keine Aufgabe an (HTTP ${a.code})`); + ok(a.json?.fehler === "nur_leitung_legt_an", + `und bekommt einen Grund, der einen Satz hat (${a.json?.fehler})`); } diff --git a/server/workspace-aufgaben.js b/server/workspace-aufgaben.js index baaa906d..5c68ee4a 100644 --- a/server/workspace-aufgaben.js +++ b/server/workspace-aufgaben.js @@ -10,7 +10,7 @@ import express from "express"; import { - db, protokolliere, echteIp, sitzungLesen, betreutWo, istLeitung, darfAufgabenVerteilen, ohneDogFather, heuteLokal, ROLLEN_SORTIERUNG, ROLLEN_GRUPPE, betreuteIds, + db, protokolliere, echteIp, sitzungLesen, betreutWo, istLeitung, darfAufgabenVerteilen, darfAufgabenAnlegen, ohneDogFather, heuteLokal, ROLLEN_SORTIERUNG, ROLLEN_GRUPPE, betreuteIds, externPruefen, externSql, sichtbarePersonenIds, sichtbareCreatorIds, MODI_KATEGORIEN, kategorienFuer, kategoriePersonen, KANAELE, kanaeleFuer, @@ -209,10 +209,32 @@ function sichtbarRoh(person) { `case` ohne `break` faellt in den naechsten -- genau das ist hier gewollt und der kuerzeste ehrliche Weg, "diese beiden gleich" zu sagen. */ + /* ================================================================= + EIN MODI SIEHT NUR SEINE EIGENEN (22.09.2026) -- und das dreht + die Entscheidung vom 09.09. ausdruecklich um. + + Filipe, mehrfach und zuletzt unmissverstaendlich: "die modis + sollen immer nur ihre aufgaben auch sehen und nicht die von + anderen, so wie bei den daten ... damit wir endlich den modis + aufgaben anstaendig verteilen koennen und sie sich nicht selber + aufgaben geben." + + Am 09.09. hatte er das Gegenteil entschieden ("ja, sie sind + untereinander ein team"), damit ein Schichttausch ohne Umweg + geht. Diese Zeile haelt beides fest, damit niemand spaeter die + aeltere Entscheidung findet und sie fuer die gueltige haelt: Die + neuere gilt. + + WAS BLEIBT: Was ihm ueber `aufgaben_zuteilung` gegeben wurde, + sieht er weiterhin -- das haengt `mitZugeteilten()` an diese + Bedingung an. Ein Pool, in dem er steht, bleibt also sichtbar, + bis ihn jemand uebernimmt. */ + case "modi": + return { wo: "a.verantwortlich_id = ?", werte: [person.id] }; + case "hand": /* Die linke Hand sieht dasselbe wie die rechte (21.09.2026). */ - case "linke": - case "modi": { + case "linke": { const liste = [...TEAM_DOGI_ROLLEN].map((r) => `'${r}'`).join(", "); const modis = db().prepare( `SELECT id FROM personen WHERE rolle IN (${liste})`).all().map((z) => z.id); @@ -777,6 +799,13 @@ aufgabenRouter.delete("/workspace/api/notizen/:id", gleicheHerkunft, (req, res) aufgabenRouter.post("/workspace/api/aufgaben", gleicheHerkunft, (req, res) => { try { + /* IM TEAM DOGI LEGT NUR DIE LEITUNG AN (22.09.2026). Ein Modi + bekommt Aufgaben; er gibt sich keine. Die Schranke steht VOR der + Feldpruefung, damit die Antwort nicht erst ueber Feldfehler + redet, wenn der Weg ohnehin zu ist. */ + if (!darfAufgabenAnlegen(req.person)) { + return res.status(403).json({ fehler: "nur_leitung_legt_an" }); + } const { aus, fehler } = pruefeFelder(req.body || {}, { neu: true, person: req.person }); if (fehler.length) return res.status(400).json({ fehler: fehler.join(" ") }); diff --git a/server/workspace.js b/server/workspace.js index c9aec03b..bad63857 100644 --- a/server/workspace.js +++ b/server/workspace.js @@ -269,6 +269,23 @@ export const istDogFather = (person) => !!person && person.rolle === "admin"; spicy und manager bleiben drin: Auf der Agenturseite verteilen sie seit jeher Aufgaben, und daran soll sich nichts aendern. */ +/** Wer eine Aufgabe ANLEGEN darf. + * + * IM TEAM DOGI KOMMEN AUFGABEN VON DER LEITUNG (22.09.2026). Filipe: + * "sie sich nicht selber aufgaben geben" und "die modis sollen nur + * diese aufgaben wo sie von den drauf markiert werden annehmen + * koennen". + * + * Das gilt AUSDRUECKLICH NUR im Team Dogi. In der Agentur legt + * weiterhin jeder fuer sich selbst an -- dort ist eine Aufgabe eine + * Notiz an sich selbst, kein Auftrag von jemandem. Eine Regel, die + * beide Haeuser ueber einen Kamm schert, waere hier falsch. */ +export const darfAufgabenAnlegen = (person) => { + if (!person) return false; + if (TEAM_DOGI_ROLLEN.has(person.rolle)) return darfAufgabenVerteilen(person); + return true; +}; + export const darfAufgabenVerteilen = (person) => istLeitung(person) || istHand(person); @@ -1469,12 +1486,50 @@ const MEINE_ENTWICKLUNG_KACHEL = { name: "Deine Entwicklung", unter: "Was sich bei dir bewegt hat – ohne Note", }; +/* DER MODI BEKOMMT DENSELBEN BEREICH WIE DIE LEITUNG (22.09.2026). + + Filipe zum Bildschirmfoto der Gruppe "Entwicklung & Nachwuchs": + "die modis sollen diesen bereich und diese zwei kacheln auch sehen, + die sollen aber nur ihre aufgaben und daten sehen." + + DIESELBEN ZWEI KACHELN, NICHT EIGENE MIT ANDEREM NAMEN. Bis heute + standen hier MEINE_AUFGABEN_KACHEL und MEINE_ENTWICKLUNG_KACHEL -- + zwei Kacheln mit denselben Zielen und anderen Namen. Zwei Namen fuer + dieselbe Sache ist genau der Fehler, der am 19.09. schon einmal zwei + Kacheln "Chat" ergeben hat: Man klickt den falschen und sucht den + Unterschied. + + "TALENTE" BLEIBT DRAUSSEN. Dort stehen Notizen ueber Zuschauer, die + nichts davon wissen -- das ist etwas anderes als die eigene + Entwicklung. Der Riegel dafuer sitzt ohnehin in rechte.js; diese + Zeile sorgt nur dafuer, dass gar nicht erst eine Kachel dorthin + zeigt. + + DASS ER DORT NUR SICH SELBST SIEHT, entscheiden die Seiten: In + workspace-werdegang.js steht `leitung ? alle : []`, in + workspace-entwicklungs-punkte.js dasselbe. Die Kachel oeffnet die + Seite -- was darauf steht, entscheidet der Server. */ const MODI_MIT_TREFF = [...MODI_BEREICHE, BEFINDEN_KACHEL, - MEINE_AUFGABEN_KACHEL, MEINE_ENTWICKLUNG_KACHEL, ...TREFF_BEREICHE, + ENTWICKLUNG_KACHEL, WERDEGANG_KACHEL, ...TREFF_BEREICHE, TREFF_MODERATION_KACHEL]; const HAND_MIT_TREFF = [...HAND_BEREICHE, ...TREFF_BEREICHE, TREFF_MODERATION_KACHEL, HILFE_KACHEL]; +/* DIE LINKE HAND SIEHT "DEIN TEAM" NICHT (22.09.2026). + + Filipe: "die rolle linke hand soll die kachel dein team auch nicht + sehen bitte danke." + + ABGELEITET, NICHT NACHGEBAUT: Ihre Liste ist die der rechten Hand + MINUS dieser einen Kachel. Eine zweite, eigene Liste waere die, die + beim naechsten neuen Bereich auseinanderlaeuft -- dann haette sie + ihn, und die linke Hand nicht, und niemand wuesste warum. + + Erkannt wird die Kachel an ihrem ZIEL, nicht an ihrem Namen: Der + Name ist am 17.09. schon einmal gewandert ("Eingang" -> "Dein + Team"), das Ziel nicht. */ +const LINKE_MIT_TREFF = HAND_MIT_TREFF.filter((k) => k.ziel !== EINGANG_KACHEL.ziel); + /* AUSSEN_ROLLEN kommt aus crew-adresse.js und wird hier nur weitergereicht -- die Adressregel braucht sie zuerst, und diese Datei importiert von dort. Eine zweite Menge waere die, die auseinanderlaeuft. */ @@ -1559,6 +1614,9 @@ const TREFF_MIT_EIGENEM = [...TREFF_BEREICHE, HILFE_KACHEL, STECKBRIEF_KACHEL_TR export function bereicheFuer(person) { if (person?.rolle === "modi") return MODI_MIT_TREFF; + /* Die linke Hand vor der allgemeinen Hand-Regel -- sonst faenge + `istHand()` sie ab, und der Filter darunter liefe nie. */ + if (person?.rolle === "linke") return LINKE_MIT_TREFF; if (istHand(person)) return HAND_MIT_TREFF; /* DIE COMMUNITY SIEHT DEN TREFF UND SONST NICHTS (11.09.2026) -- seit dem 19.09. plus den eigenen Steckbrief. */ @@ -5616,6 +5674,9 @@ workspaceRouter.get("/workspace/api/ich", (req, res) => { Aus DERSELBEN Funktion, die auch die Route benutzt. */ darf_verteilen: darfAufgabenVerteilen(person), + /* Damit die Oberflaeche den Knopf gar nicht erst anbietet -- ein + Knopf, der mit 403 antwortet, ist schlimmer als keiner. */ + darf_aufgaben_anlegen: darfAufgabenAnlegen(person), /* DIE KACHELN, WENN SIE NICHT IM BROWSER STEHEN DUERFEN. Fuer die fuenf bekannten Rollen steht hier `null`, und die diff --git a/workspace/anruf-probe.html b/workspace/anruf-probe.html index 71c05259..9c14d79f 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`. --> - - + + - +