Der Treff: eine eigene Tür für die Community, und sie sieht nur, was dasteht
Filipe: "eine community rolle und community kategorie, wo die community auch dann nur die sieht" · "wieso nur eine kachel — ich will mehrere, mit mehreren optionen" · "egal welche rolle hinzugefügt wird soll immer nur das sehen was ich erlaube". DIE DRITTE ADRESSE. treff.dogfather-universe.com bekommt eine eigene Weiche (treff-adresse.js), eine eigene Zugangswand, ein eigenes Manifest und acht eigene Bühnenbilder. Ohne sie stünde dort die Wand der Agentur: Spicy-Logo, "Creator Workspace", fünf Rollenkacheln mit den Namen Admin, Manager, Scout, Creator — die komplette Struktur des Unternehmens, vor der Anmeldung, für jeden mit der Adresse. Welche Wand zu welcher Tür gehört, steht jetzt in EINER Tafel (istFremdeWand) statt als Sonderfall im Code. Bei zwei Wänden war ein Sonderfall richtig; bei drei wären es drei geworden, bei vier sechs. SIEBEN BRETTER UND EIN ACHTES NUR FÜRS TEAM. Anschlagbrett, Was ansteht, Der Treff, Wunschliste, Highlights, Regeln & Hilfe, Mitmachen — dazu "Meldungen & Maßnahmen", das ausdrücklich NICHT in TREFF_BEREICHE steht: dort wäre es lautlos bei der Community gelandet und hätte ausgesehen wie die anderen sieben. WAS AUF DEN BRETTERN PASSIERT: "Will ich auch" (eine Stimme je Person, erzwungen durch den Schlüssel, nicht durch eine Prüfung) · Anheften, höchstens drei, gezählt IN der Transaktion · Freigabe vor Sichtbarkeit für Termine und Highlights, wobei Abwesenheit der Ruhezustand ist · Melden mit Pflicht-Grund (DSA Art. 16) · Entfernen mit Grund, der den Beitrag ÜBERLEBT (DSA Art. 17) · drei Stufen, gerechnet statt gespeichert · die Bannleiter: Modi bis 7 Tage, dauerhaft nur DogFather (seine Entscheidung) · "Mitmachen" wird zum Talent, genau einmal. Der Ausschluss wirkt in sitzungLesen() — also nicht nur beim Schreiben. Wer ausgeschlossen ist, ist weg, nicht stumm. ZWEI SEITEN MEHR. treff-regeln.html holt seine ZAHLEN vom Server (Mindestalter 18, Fristen, Anschläge) — ein Regeltext, der eine andere Zahl nennt als die Regel, ist schlimmer als keiner. rechte.html rechnet "Wer sieht was" aus derselben Tafel aus, aus der die Schranke ihre Entscheidung holt. Die Community steht dort bei 3 von 23. SECHS BEFUNDE, KEINEN HAT DAS LESEN GEFUNDEN: · Ein Modi kam über den verborgenen Zugang in den Treff — die Bedingung war durch Ausschluss formuliert und nahm die neue Wand automatisch mit · /api/personen gab einem Mitglied Namen und Rolle von DogFather · Ein DELETE mit Körper wird von Nodes HTTP-Parser mit einem leeren 400 abgewiesen, bevor Express ihn sieht (gemessen). Der Grund reist jetzt in der Adresse · Der Kommentar, der erklärt, warum die Zugangswand keine Rollennamen nennt, nannte selbst einen — in einer ausgelieferten Datei · Zwei Listen für "welche Seiten sind ohne Anmeldung offen". Sie stimmten, weil beide am selben Tag entstanden · Ein Portkonflikt, den ich selbst gebaut hatte (4391 gehört pruef-chat-aufloesen) Dazu zwei feste Zahlen abgeschafft (die 20 in pruef-rechtetafel, die Kachelzahl in pruef-treff) und zwei Werkzeuge, die jetzt SUCHEN statt aufzuzählen: Der Versionsstempel findet seine Manifeste selbst — das dritte hätte sonst keinen bekommen, und die neue App hätte bis zu vier Stunden lang das falsche Zeichen getragen. Das Bildwerkzeug baut beide Zugangswände aus einer Vorlage mit zwei Werten. Zwei neue Kacheltöne, gemessen statt gewählt: #2f2f7f (Abstand 31,4 in Lab) und #7c2771 (29,7). Das schwächste Paar der vorhandenen 34 liegt bei 24,9. Geprüft: treff 69 · treff-werkzeuge 60 · rollen 312 · start-ansicht 147 · crew-adresse 129 · sicht 84 · modi-verborgen 80 · haus-trennung 62 · bereiche-lesend 37 · css-klassen 30 · zwischenspeicher 21 · alle-wege 19 · rechtetafel 19 — alles grün. Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
+353
-13
@@ -19,14 +19,178 @@ import {
|
||||
db, protokolliere, echteIp, sitzungLesen, betreutWo, darfCreator, betreuteIds, istLeitung, istDogFather, siehtAlles, istSpicy, ohneDogFather,
|
||||
externPruefen, externSql,
|
||||
ohneTeamDogi, ohneAgentur, siehtModis, fuehrtTeamDogi, MODI_BEREICHE_ERLAUBT, TEAM_DOGI_ROLLEN,
|
||||
TREFF_BRETTER, TREFF_ROLLEN, AUSSEN_ROLLEN,
|
||||
} from "./workspace.js";
|
||||
import { nachrichtSchicken } from "./workspace-chat.js";
|
||||
import {
|
||||
darfSchreiben, freigabeBedingung, entfernenVorbereiten, TREFF_TEAM_ROLLEN,
|
||||
mitRollenname,
|
||||
} from "./workspace-treff.js";
|
||||
|
||||
export const bereicheRouter = express.Router();
|
||||
|
||||
/* Die Bereiche und ihre Arten. Bewusst hier und nicht in der Datenbank:
|
||||
Es sind Festlegungen aus dem Konzept, keine Nutzdaten. */
|
||||
export const BEREICHE = {
|
||||
/* =====================================================================
|
||||
DIE SIEBEN BRETTER DES TREFFS (11.09.2026)
|
||||
|
||||
Der Raum fuer die Zuschauer. Sie laufen ueber dieselbe Maschinerie
|
||||
wie Ideen-Board und Angebote -- ein Bereich, seine Arten, dieselbe
|
||||
Seite. Eine eigene Bauart daneben waere eine zweite
|
||||
Sichtbarkeitsregel, und genau deren Vervielfaeltigung hat am
|
||||
10.09. ein Leck verursacht.
|
||||
|
||||
ALLE SIEBEN HABEN `fuerAlle`: Im Treff sieht jeder jeden Beitrag.
|
||||
Ein Raum, in dem man nur sieht, was man selbst geschrieben hat,
|
||||
waere kein Raum. Die Grenze nach aussen zieht nicht `fuerAlle`,
|
||||
sondern der Riegel in sichtbarEintrag() -- die Agentur sieht kein
|
||||
einziges dieser Bretter.
|
||||
|
||||
ALLE SIEBEN HABEN `ohneCreatorBezug`: Hier geht es um niemanden aus
|
||||
der Agentur. Das Feld waere nicht nur ueberfluessig, es waere die
|
||||
Einladung, versehentlich einen Creator mit einem Zuschauer zu
|
||||
verknuepfen.
|
||||
===================================================================== */
|
||||
|
||||
anschlag: {
|
||||
name: "Anschlagbrett",
|
||||
ober: "Vom Team",
|
||||
arten: {
|
||||
ansage: "Ansage",
|
||||
regel: "Neue Regel",
|
||||
hinweis: "Hinweis",
|
||||
danke: "Danke an euch",
|
||||
},
|
||||
bewertung: false,
|
||||
dringlichkeit: false,
|
||||
ohneCreatorBezug: true,
|
||||
fuerAlle: true,
|
||||
},
|
||||
|
||||
ansteht: {
|
||||
name: "Was ansteht",
|
||||
ober: "Termine",
|
||||
/* AUSDRUECKLICH NICHT AN DEN ECHTEN KALENDER GEKOPPELT.
|
||||
|
||||
Ein Termin traegt Titel, Ort und Gegenueber -- und die Regel im
|
||||
Haus lautet seit dem 07.09., dass ein Kalender als Ganzes privat
|
||||
ist. Eine Filterung waere eine Einstellung, die man falsch setzen
|
||||
kann; ein Eintrag hier ist eine Entscheidung, die jemand trifft.
|
||||
Der Preis ist, dass das Team es zweimal schreibt. Das ist der
|
||||
guenstigere von beiden. */
|
||||
arten: {
|
||||
stream: "Stream",
|
||||
event: "Event",
|
||||
turnier: "Turnier",
|
||||
pause: "Keine Sendung",
|
||||
},
|
||||
bewertung: false,
|
||||
dringlichkeit: false,
|
||||
ohneCreatorBezug: true,
|
||||
fuerAlle: true,
|
||||
},
|
||||
|
||||
treff: {
|
||||
name: "Der Treff",
|
||||
ober: "Euer Raum",
|
||||
/* DIE REIHENFOLGE IST ABSICHT. Das erste Feld bestimmt, was
|
||||
geschrieben wird -- wer ein Formular oeffnet, dessen erste
|
||||
Auswahl "Problem" heisst, schreibt Probleme auf.
|
||||
|
||||
"Hallo, ich bin neu" steht vorn, weil die ersten sieben Tage
|
||||
darueber entscheiden, ob jemand bleibt: Wer in dieser Zeit
|
||||
erlebt, dass er hier einen Platz hat, kommt deutlich haeufiger
|
||||
wieder. Jede Vorstellung bekommt eine Antwort -- das ist der
|
||||
ganze Trick, und er steht in keinem Code. */
|
||||
arten: {
|
||||
hallo: "Hallo, ich bin neu",
|
||||
frage: "Frage",
|
||||
lob: "Das war gut",
|
||||
problem: "Etwas stimmt nicht",
|
||||
},
|
||||
bewertung: false,
|
||||
dringlichkeit: false,
|
||||
ohneCreatorBezug: true,
|
||||
fuerAlle: true,
|
||||
},
|
||||
|
||||
wunsch: {
|
||||
name: "Wunschliste",
|
||||
ober: "Was ihr euch wuenscht",
|
||||
arten: {
|
||||
stream: "Fuer den Stream",
|
||||
technik: "Technik",
|
||||
gemeinsam: "Fuer die Community",
|
||||
sonstiges: "Sonstiges",
|
||||
},
|
||||
bewertung: false,
|
||||
/* KEINE DRINGLICHKEIT VON EINEM EINZELNEN. Was wichtig ist,
|
||||
entscheidet hier nicht der Schreiber, sondern wie viele
|
||||
mitwollen -- "Will ich auch" kommt als naechster Schritt. Eine
|
||||
Dringlichkeit daneben waere eine zweite Rangordnung, und die
|
||||
beiden wuerden einander widersprechen. */
|
||||
dringlichkeit: false,
|
||||
ohneCreatorBezug: true,
|
||||
fuerAlle: true,
|
||||
},
|
||||
|
||||
highlight: {
|
||||
name: "Highlights",
|
||||
ober: "Von euch",
|
||||
arten: {
|
||||
clip: "Clip",
|
||||
bild: "Bild",
|
||||
fanart: "Fanart",
|
||||
moment: "Moment",
|
||||
},
|
||||
bewertung: false,
|
||||
dringlichkeit: false,
|
||||
ohneCreatorBezug: true,
|
||||
fuerAlle: true,
|
||||
},
|
||||
|
||||
regeln: {
|
||||
name: "Regeln & Hilfe",
|
||||
ober: "Wie es hier laeuft",
|
||||
/* REGELN IN EINFACHER SPRACHE UND AN ECHTEN FAELLEN. Vage Regeln
|
||||
erzeugen Grenzfaelle, und die muss dann jeder Modi einzeln
|
||||
entscheiden -- das ist der Weg, auf dem ein Team uneinheitlich
|
||||
wird und die Community es merkt. */
|
||||
arten: {
|
||||
regel: "Regel",
|
||||
frage: "Haeufige Frage",
|
||||
hilfe: "Hilfe",
|
||||
folge: "Was passiert, wenn",
|
||||
},
|
||||
bewertung: false,
|
||||
dringlichkeit: false,
|
||||
ohneCreatorBezug: true,
|
||||
fuerAlle: true,
|
||||
},
|
||||
|
||||
mitmachen: {
|
||||
name: "Mitmachen",
|
||||
ober: "Nachwuchs",
|
||||
/* DIE BRUECKE ZU DEN TALENTEN. Wer sich hier meldet, ist ein
|
||||
Kandidat -- und Kandidaten gehoeren in die Kategorie, die es
|
||||
dafuer schon gibt, nicht in eine zweite Liste daneben.
|
||||
|
||||
Daneben gehoert der ehrliche Satz, dass eine Bewerbung nicht der
|
||||
Hauptweg ist: Der treffsicherste Weg ist, dass jemandem aus dem
|
||||
Team auffaellt, wie du dich verhaeltst. Das steht so im Brett,
|
||||
weil es stimmt -- und weil es die richtige Erwartung setzt. */
|
||||
arten: {
|
||||
gesucht: "Wir suchen",
|
||||
lust: "Ich haette Lust",
|
||||
frage: "Frage dazu",
|
||||
},
|
||||
bewertung: false,
|
||||
dringlichkeit: false,
|
||||
ohneCreatorBezug: true,
|
||||
fuerAlle: true,
|
||||
},
|
||||
|
||||
live: {
|
||||
name: "LIVE-Analyse",
|
||||
arten: { vorbereitung: "Vorbereitung", mitschrift: "Während LIVE", auswertung: "Auswertung" },
|
||||
@@ -483,9 +647,30 @@ bereicheRouter.use("/workspace/api/bereich/:bereich", (req, res, next) => {
|
||||
sie ueber die Adresszeile in die Agentur-Ablage, die sie nichts
|
||||
angeht. Genau die Luecke, gegen die diese Schranke gebaut wurde,
|
||||
nur eine Rolle spaeter. */
|
||||
const b = String(req.params.bereich);
|
||||
const nein = () => res.status(404).json({ fehler: "nicht_gefunden" });
|
||||
|
||||
/* EINE AUSSENROLLE KOMMT NUR IN DEN TREFF (11.09.2026).
|
||||
|
||||
Und zwar als ERSTER Zweig, nicht als letzter. Die Zeile darunter
|
||||
hiess bis heute "wer nicht zum Team gehoert, darf weiter" -- fuer
|
||||
einen Gast waere das ein Freifahrtschein durch alle achtzehn
|
||||
Bereiche gewesen, obwohl die Kacheln ihm nur sieben anbieten. Eine
|
||||
Regel, die nur im Formular gilt, ist keine Regel. */
|
||||
if (AUSSEN_ROLLEN.has(req.person?.rolle)) {
|
||||
return TREFF_BRETTER.includes(b) ? next() : nein();
|
||||
}
|
||||
|
||||
/* UND UMGEKEHRT: Wer nicht zum Treff gehoert, kommt nicht hinein.
|
||||
Das ist derselbe Riegel wie in sichtbarEintrag(), nur eine Ebene
|
||||
frueher -- dort entscheidet er, welche ZEILEN jemand sieht, hier,
|
||||
ob die Seite ueberhaupt antwortet. Zwei Schloesser, absichtlich:
|
||||
Faellt eines weg, haelt das andere. */
|
||||
if (TREFF_BRETTER.includes(b) && !TREFF_ROLLEN.has(req.person?.rolle)) return nein();
|
||||
|
||||
if (!TEAM_DOGI_ROLLEN.has(req.person?.rolle)) return next();
|
||||
if (MODI_BEREICHE_ERLAUBT.has(String(req.params.bereich))) return next();
|
||||
return res.status(404).json({ fehler: "nicht_gefunden" });
|
||||
if (MODI_BEREICHE_ERLAUBT.has(b)) return next();
|
||||
return nein();
|
||||
});
|
||||
|
||||
/* ---------- Die Bereiche sind fuer Creator zum LESEN da ----------------
|
||||
@@ -713,7 +898,65 @@ function ohneVertrauliche(regel, person, praefix) {
|
||||
};
|
||||
}
|
||||
|
||||
/* =====================================================================
|
||||
DER TREFF HAT ZWEI RIEGEL, UND SIE ZEIGEN IN ENTGEGENGESETZTE
|
||||
RICHTUNGEN (11.09.2026)
|
||||
|
||||
Filipe: "wo die community auch dan nur die sieht und die modis
|
||||
rechte hand und ich also dogfather sehen die aber auch. die
|
||||
community aber nur die dann."
|
||||
|
||||
Daraus folgen zwei Saetze, und beide muessen gelten:
|
||||
|
||||
1. EINE AUSSENROLLE SIEHT NUR DEN TREFF. Nicht "den Treff und was
|
||||
sonst noch durchfaellt" -- nur ihn. Deshalb steht dieser Zweig
|
||||
GANZ VORN und baut seine Regel selbst, statt auf der
|
||||
allgemeinen aufzusetzen. Wer auf einer bestehenden Regel
|
||||
aufsetzt, erbt jeden Zweig, den sie hat, auch die, die es
|
||||
morgen erst gibt.
|
||||
|
||||
2. DIE AGENTUR SIEHT DEN TREFF NICHT. Creator, Scouts, Manager und
|
||||
Spicy Media haben mit den Zuschauern dieses Streams nichts zu
|
||||
tun. Ohne diesen zweiten Riegel haette `fuerAlle` sie
|
||||
hereingelassen -- genau das Loch, das am 10.09. schon einmal
|
||||
entstanden ist, nur andersherum.
|
||||
|
||||
BEIDE STEHEN HIER UND NICHT IN sichtbar(). Diese Funktion beantwortet
|
||||
auch Fragen zu Aufgaben, Dateien und Terminen; ein Bereichsname hat
|
||||
dort nichts zu suchen. Der Kommentar eine Bildschirmseite weiter oben
|
||||
warnt woertlich davor. */
|
||||
export function sichtbarEintrag(person, praefix = "e") {
|
||||
/* RIEGEL 1 -- die Aussenrolle. Eine eigene, vollstaendige Regel:
|
||||
genau die Bretter des Treffs, sonst nichts. */
|
||||
if (AUSSEN_ROLLEN.has(person?.rolle)) {
|
||||
const platz = TREFF_BRETTER.map(() => "?").join(", ");
|
||||
const grund = { wo: `${praefix}.bereich IN (${platz})`, werte: [...TREFF_BRETTER] };
|
||||
/* RIEGEL 1b -- WAS NOCH NICHT FREIGEGEBEN IST, GIBT ES NICHT
|
||||
(11.09.2026). Termine und Highlights erscheinen der Community
|
||||
erst, wenn jemand aus dem Team sie freigegeben hat.
|
||||
|
||||
DIE BEDINGUNG HAENGT HIER UND NICHT AM LESE-WEG, weil sie sonst
|
||||
nur dort gaelte: Suche, Ausfuhr und jeder kuenftige Weg, der
|
||||
sichtbarEintrag benutzt, haetten die unfreigegebenen Zeilen
|
||||
weiterhin geliefert. Genau so ist am 10.09. ein Modi-Eintrag
|
||||
durch die Suche gekommen, obwohl das Brett zu war. */
|
||||
const frei = freigabeBedingung(person, praefix);
|
||||
if (!frei) return grund;
|
||||
return { wo: `(${grund.wo}) AND ${frei.wo}`, werte: [...grund.werte, ...frei.werte] };
|
||||
}
|
||||
const regel = sichtbarRoh2(person, praefix);
|
||||
/* RIEGEL 2 -- wer nicht zum Treff gehoert, sieht seine Bretter nicht.
|
||||
Auch DogFather geht hier durch; er steht in TREFF_ROLLEN und faellt
|
||||
deshalb nicht heraus. */
|
||||
if (!regel || TREFF_ROLLEN.has(person?.rolle)) return regel;
|
||||
const platz = TREFF_BRETTER.map(() => "?").join(", ");
|
||||
return {
|
||||
wo: `(${regel.wo}) AND ${praefix}.bereich NOT IN (${platz})`,
|
||||
werte: [...regel.werte, ...TREFF_BRETTER],
|
||||
};
|
||||
}
|
||||
|
||||
function sichtbarRoh2(person, praefix = "e") {
|
||||
const regel = sichtbar(person);
|
||||
if (!regel) return regel;
|
||||
if (regel.wo === "1=1") return regel; // DogFather sieht ohnehin alles
|
||||
@@ -773,6 +1016,34 @@ function saeulePasst(saeuleId, creatorId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/* =====================================================================
|
||||
WAS EIN TREFF-BRETT ZUSAETZLICH MITBRINGT (11.09.2026)
|
||||
|
||||
Drei Angaben, die es nur dort gibt: wie viele "Will ich auch" ein
|
||||
Wunsch hat, ob meine Stimme dabei ist, ob die Ansage angeheftet und
|
||||
ob der Eintrag freigegeben ist.
|
||||
|
||||
SIE HAENGEN NICHT AN SPALTEN, sondern werden nur fuer die sieben
|
||||
Bretter angehaengt. Drei Unterabfragen je Zeile sind hier
|
||||
bedeutungslos (die Tabellen haben eine Handvoll Zeilen), auf den
|
||||
Betreuungsbrettern waeren sie es nicht -- und vor allem waeren sie
|
||||
dort eine Auskunft ueber etwas, das es in diesem Bereich gar nicht
|
||||
gibt.
|
||||
|
||||
DER ROLLENNAME KOMMT MIT (Entscheidung Filipe, 11.09.2026: "voller
|
||||
Rollenname zeigen"). Er kommt als ROLLE, der Klartext wird erst in
|
||||
der Antwort gebildet -- eine Zuordnung Rolle -> Name im
|
||||
ausgelieferten JavaScript waere eine Liste aller Rollen dieses
|
||||
Hauses auf jedem Rechner der Community.
|
||||
===================================================================== */
|
||||
const TREFF_SPALTEN = `,
|
||||
(SELECT COUNT(*) FROM treff_stimmen ts WHERE ts.eintrag_id = e.id) AS stimmen,
|
||||
(SELECT COUNT(*) FROM treff_stimmen ts
|
||||
WHERE ts.eintrag_id = e.id AND ts.person_id = ?) AS meine_stimme,
|
||||
(SELECT COUNT(*) FROM treff_angeheftet ta WHERE ta.eintrag_id = e.id) AS angeheftet,
|
||||
(SELECT COUNT(*) FROM treff_freigaben tf WHERE tf.eintrag_id = e.id) AS freigegeben,
|
||||
pe.rolle AS erstellt_rolle`;
|
||||
|
||||
const VERBUND = `
|
||||
FROM eintraege e
|
||||
LEFT JOIN personen pc ON pc.id = e.creator_id
|
||||
@@ -789,15 +1060,43 @@ bereicheRouter.get("/workspace/api/bereich/:bereich", (req, res) => {
|
||||
const regel = sichtbarEintrag(req.sicht || req.person);
|
||||
if (!regel) return res.status(404).json({ fehler: "nicht_gefunden" });
|
||||
|
||||
const eintraege = db().prepare(`
|
||||
SELECT ${SPALTEN} ${VERBUND}
|
||||
WHERE ${regel.wo} AND e.bereich = ?
|
||||
ORDER BY
|
||||
CASE e.status WHEN 'offen' THEN 0 ELSE 1 END,
|
||||
CASE e.dringlichkeit WHEN 'hoch' THEN 0 WHEN 'mittel' THEN 1 ELSE 2 END,
|
||||
e.datum DESC, e.id DESC`).all(...regel.werte, bereich);
|
||||
const treffBrett = TREFF_BRETTER.includes(bereich);
|
||||
|
||||
res.json({ bereich, einstellung, eintraege });
|
||||
/* DIE REIHENFOLGE GEHOERT ZUM BRETT (11.09.2026).
|
||||
|
||||
Am Anschlagbrett steht oben, was angeheftet ist -- sonst waere
|
||||
das Anheften eine Zierde. Auf der Wunschliste steht oben, was die
|
||||
meisten wollen; genau das ist der Sinn von "Will ich auch", und
|
||||
eine Liste nach Datum haette die Abstimmung unsichtbar gemacht.
|
||||
Ueberall sonst bleibt es, wie es war. */
|
||||
const reihenfolge = bereich === "anschlag"
|
||||
? "angeheftet DESC, e.datum DESC, e.id DESC"
|
||||
: bereich === "wunsch"
|
||||
? "stimmen DESC, e.datum DESC, e.id DESC"
|
||||
: `CASE e.status WHEN 'offen' THEN 0 ELSE 1 END,
|
||||
CASE e.dringlichkeit WHEN 'hoch' THEN 0 WHEN 'mittel' THEN 1 ELSE 2 END,
|
||||
e.datum DESC, e.id DESC`;
|
||||
|
||||
const wer = (req.sicht || req.person)?.id ?? 0;
|
||||
const eintraege = db().prepare(`
|
||||
SELECT ${SPALTEN}${treffBrett ? TREFF_SPALTEN : ""} ${VERBUND}
|
||||
WHERE ${regel.wo} AND e.bereich = ?
|
||||
ORDER BY ${reihenfolge}`)
|
||||
.all(...(treffBrett ? [wer] : []), ...regel.werte, bereich);
|
||||
|
||||
/* DASS DIES EIN BRETT DES TREFFS IST, SAGT DER SERVER (11.09.2026).
|
||||
|
||||
Die Oberflaeche braucht die Auskunft, um ihre Knoepfe zu bauen
|
||||
("Will ich auch", anheften, freigeben, melden). Sie koennte den
|
||||
Bereichsnamen gegen eine Liste im Browser halten -- dann stuenden
|
||||
die Namen aller sieben Bretter in einer ausgelieferten Datei, und
|
||||
es gaebe eine zweite Wahrheit darueber, welche es sind. So gibt
|
||||
es weiterhin genau eine (TREFF_BRETTER), und der Browser fragt
|
||||
sie, statt sie zu kennen. */
|
||||
res.json({
|
||||
bereich, einstellung, treff: treffBrett,
|
||||
eintraege: treffBrett ? eintraege.map(mitRollenname) : eintraege,
|
||||
});
|
||||
} catch (fehler) {
|
||||
console.error("[workspace] Bereich lesen:", fehler?.message);
|
||||
res.status(503).json({ fehler: "nicht_verfuegbar" });
|
||||
@@ -1062,6 +1361,20 @@ bereicheRouter.post("/workspace/api/bereich/:bereich", gleicheHerkunft, (req, re
|
||||
const regel = sichtbar(req.person);
|
||||
if (!regel) return res.status(404).json({ fehler: "nicht_gefunden" });
|
||||
|
||||
/* DIE SCHREIBTAFEL DES TREFFS (11.09.2026).
|
||||
|
||||
Auf welches der sieben Bretter jemand von aussen schreiben darf,
|
||||
steht in TREFF_SCHREIBEN -- an einer Stelle, aus der auch die
|
||||
Oberflaeche ihre Knoepfe holt (/api/treff/lage). Waeren es zwei
|
||||
Stellen, koennte ein Knopf erscheinen, den der Server ablehnt --
|
||||
oder, schlimmer, umgekehrt.
|
||||
|
||||
DER TEXT WIRD DURCHGEREICHT, nicht durch "nicht_erlaubt" ersetzt:
|
||||
"Ab Dabei kannst du hier schreiben" beantwortet die Frage, die
|
||||
der Mensch davor gerade hat. */
|
||||
const warum = darfSchreiben(req.person, bereich);
|
||||
if (warum) return res.status(403).json({ fehler: warum });
|
||||
|
||||
const { aus, fehler } = pruefe(bereich, req.body || {}, { neu: true });
|
||||
if (fehler.length) return res.status(400).json({ fehler: fehler.join(" ") });
|
||||
|
||||
@@ -1226,9 +1539,36 @@ bereicheRouter.delete("/workspace/api/bereich/:bereich/:id", gleicheHerkunft, (r
|
||||
/* Löschen darf das Management und wer den Eintrag selbst geschrieben
|
||||
hat -- sonst könnte ein Creator eine Notiz des Managements über
|
||||
seinen eigenen Bereich verschwinden lassen. */
|
||||
if (!istLeitung(req.person) && eintrag.erstellt_von !== req.person.id) {
|
||||
return res.status(403).json({ fehler: "nicht_erlaubt" });
|
||||
}
|
||||
/* IM TREFF RAEUMT AUCH EIN MODI AUF (11.09.2026). Er ist dort die
|
||||
Moderation; waere Aufraeumen der Leitung vorbehalten, bliebe ein
|
||||
Beitrag stehen, bis jemand Zeit hat -- und genau in dieser Zeit
|
||||
liest ihn die Community. */
|
||||
const treffBrett = TREFF_BRETTER.includes(bereich);
|
||||
const darfWeg = treffBrett
|
||||
? TREFF_TEAM_ROLLEN.has(req.person.rolle) || eintrag.erstellt_von === req.person.id
|
||||
: istLeitung(req.person) || eintrag.erstellt_von === req.person.id;
|
||||
if (!darfWeg) return res.status(403).json({ fehler: "nicht_erlaubt" });
|
||||
|
||||
/* DER GRUND WIRD FESTGEHALTEN, BEVOR DER BEITRAG VERSCHWINDET
|
||||
(DSA Art. 17). Danach waere es zu spaet: Titel und Verfasser
|
||||
stuenden nirgends mehr, und eine Begruendung ohne den Beitrag,
|
||||
den sie begruendet, ist keine.
|
||||
|
||||
DER GRUND KOMMT AUS DER ADRESSE, und das ist keine Vorliebe,
|
||||
sondern gemessen (11.09.2026): Nodes HTTP-Parser weist ein
|
||||
DELETE MIT KOERPER mit einem leeren 400 ab, bevor Express die
|
||||
Anfrage ueberhaupt sieht -- eine Antwort mit genau einem
|
||||
Kopffeld ("connection: close") und ohne Text. Wer den Fehler
|
||||
sucht, sucht ihn in dieser Route, und hier ist keiner.
|
||||
|
||||
Der Koerper bleibt als zweite Moeglichkeit stehen: Er schadet
|
||||
nicht, und wenn ein anderer Weg (ein Werkzeug, eine kuenftige
|
||||
Fassung von Node) doch einen mitschickt, wird er gelesen. Zwei
|
||||
Quellen fuer denselben Wert sind hier keine zwei Wahrheiten --
|
||||
es ist derselbe Wert, nur zwei Briefkaesten. */
|
||||
const nein = entfernenVorbereiten(req.person, eintrag,
|
||||
req.body?.grund ?? req.query?.grund);
|
||||
if (nein) return res.status(400).json({ fehler: nein });
|
||||
|
||||
db().prepare("DELETE FROM eintraege WHERE id = ?").run(id);
|
||||
protokolliere("eintrag_geloescht", {
|
||||
|
||||
Reference in New Issue
Block a user