Files
dogfather-universe/server/mess-sichtbarkeit.mjs
T
DogFatherGitandClaude Opus 5 25de892fdb screen5: Aus dem Treff wird das Rudel, aus der Zentrale die IrrenAnstalt
Filipe, 22.09.2026: "ersetze die zentrale durch, Die IrrenAnstalt.
genau so geschrieben bitte. und alles was treff heißt oder wo treff
steht soll durch Rudel ersetzt werden bitte."

Die Schreibweise "IrrenAnstalt" mit grossem A in der Mitte ist so
gewollt. Das steht als Hinweis daneben, damit sie beim naechsten Mal
niemand "korrigiert".

WAS UMBENANNT WURDE: alles, was jemand LIEST -- Kachelnamen,
Ueberschriften, Markenzeilen, Saetze, Meldungen, Aufgabenvorlagen.
116 Zeilen in 42 Dateien.

WAS BLEIBT: Adressen (treff-regeln.html), Bezeichner (TREFF_ROLLEN),
Datenbankwerte (bereich = 'treff'), Abfrageteile (b=treff). Eine
Adresse umzubenennen bricht jedes Lesezeichen, und ein Datenbankwert
umzuschreiben waere eine Umstellung ohne Gegenwert. Dieselbe
Entscheidung wie heute frueh bei Dogi-Media, wo material.html auch
material.html geblieben ist.

DREI GRAMMATIKFEHLER IM EIGENEN ENTWURF, alle vor dem Ausliefern
gefunden -- ein blindes Ersetzen reicht hier nicht:

1. "der Treff" ist maennlich, "das Rudel" saechlich. Ohne Tabelle
   waere ueberall "Der Rudel" gestanden. (Und "Treffer" waere zu
   "Rudeler" geworden, "Treffen" zu "Rudelen" -- deshalb greift die
   Regel nur bei Wortgrenze und nie vor einem Kleinbuchstaben.)

2. BINDESTRICH-ZUSAMMENSETZUNGEN. In "der Treff-Chat" gehoert der
   Artikel zu "Chat", nicht zu "Treff". Der erste Durchlauf machte
   daraus "das Rudel-Chat", "das Rudel-Kacheln" und "ein Rudel-Raum".
   Jetzt greift die Artikelregel nur, wenn das Wort allein steht.

3. GESCHUETZTE LEERZEICHEN. In den Markenzeilen steht
   `Der Treff`, damit die zwei Woerter nicht umbrechen. Das
   Muster hat daran vorbeigegriffen: "Der Rudel", auf fuenf
   Seiten. Jetzt wird das Trennzeichen mitgefasst und unveraendert
   wieder eingesetzt.

Gefunden wurden alle drei, weil jede einzelne der 116 Zeilen vor dem
Schreiben als ALT/NEU ausgegeben und gelesen wurde -- und danach
gezielt nach falschen Artikeln gesucht ("den Rudel", "der Rudel",
"einen Rudel"). Uebrig blieben sechs Treffer, und die sind alle
richtig: "einen Rudel-Raum", "der Rudel-Chat", "den Rudel-Regeln" --
Zusammensetzungen, bei denen der Artikel zum letzten Wort gehoert.

UND ZWEI PRUEFUNGEN, die die Umbenennung nicht mitbekommen haetten:
`/Treff/.test(...)` und `/Treff/i.test(...)`. Ein regulaerer Ausdruck
ist keine Zeichenkette -- sie haetten ab sofort nach einem Wort
gesucht, das die Seite nicht mehr sagt, und waeren still rot geworden,
ohne dass etwas kaputt ist.

Geprueft, alle gruen: pruef-treff, pruef-treffchat,
pruef-deutsche-texte, pruef-uebernahme, pruef-crew-adresse,
pruef-willkommen, pruef-wege-nach-draussen, pruef-vorlagen,
pruef-start-ansicht, pruef-struktur.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-22 14:25:56 +02:00

158 lines
6.6 KiB
JavaScript

/* MESSUNG, KEINE PRUEFUNG (17.09.2026)
Filipe: "die community und alle anderen sollen die neuen sachen in
allen kategorien auch sehen bitte. in allen die sie sehen soll auch
jede aenderung mit gehen, immer nur in denen die ihnen erlaubt ist
zu sehen."
Die Frage: Was sieht eigentlich wer? Nicht geraten -- gemessen.
ZWEI DINGE, DIE ICH BEIM ERSTEN VERSUCH FALSCH HATTE und die jede
Zahl wertlos gemacht haben:
1. Die Community lebt auf crew., nicht auf der Agenturadresse.
Ohne den richtigen Host-Kopf kam der Gast mit 401 "ungueltig"
heraus -- und das sah aus wie ein Befund, war aber meine eigene
falsche Adresse.
2. Ein Gast bestaetigt beim Anmelden sein Alter (`alter_ok`).
Aufrufen mit: node server/mess-sichtbarkeit.mjs
*/
import { mkdtempSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { request as httpAnfrage } from "node:http";
import { portMussFreiSein } from "./helfer-port.mjs";
const PORT = await portMussFreiSein(4496, "mess-sichtbarkeit");
const ordner = mkdtempSync(join(tmpdir(), "ws-mess-"));
process.env.WORKSPACE_DB = join(ordner, "workspace.db");
process.env.PORT = String(PORT);
process.env.SITE_ACCESS_SECRET = "lokaler-test";
process.env.SITE_PUBLIC_LAUNCH_AT = "2020-01-01T00:00:00+01:00";
const express = (await import("express")).default;
const ec = express.response.cookie;
express.response.cookie = function (n, w, o) { return ec.call(this, n, w, { ...(o || {}), secure: false }); };
import { notbremse } from "./helfer-notbremse.mjs";
await import("./index.js");
notbremse(180_000, "mess-sichtbarkeit");
await new Promise((r) => setTimeout(r, 700));
const CREW = "crew.dogfather-universe.com";
const AGENTUR = "workspace.dogfather-universe.com";
const { DatabaseSync } = await import("node:sqlite");
const { scryptSync, randomBytes, createHmac } = await import("node:crypto");
const { TREFF_BRETTER } = await import("./workspace.js");
const { TREFF_FREIGABE_BRETTER } = await import("./workspace-treff.js");
const { BEREICHE } = await import("./workspace-bereiche.js");
const ALLE_BEREICHE = Object.keys(BEREICHE);
const d = new DatabaseSync(process.env.WORKSPACE_DB);
const jetzt = new Date().toISOString();
const sch = randomBytes(32).toString("hex");
d.prepare("INSERT INTO einstellungen (schluessel, wert, geaendert, von)"
+ " VALUES (?,?,?,NULL) ON CONFLICT(schluessel) DO NOTHING")
.run("code_kennung_schluessel", sch, jetzt);
const ROLLEN = ["admin", "hand", "modi", "gast"];
const codes = {};
for (const r of ROLLEN) {
const code = `CODE-${r.toUpperCase()}-0001`;
const salt = randomBytes(16).toString("hex");
const hash = scryptSync(code, salt, 64,
{ N: 32768, r: 8, p: 1, maxmem: 96 * 1024 * 1024 }).toString("hex");
d.prepare("INSERT INTO personen"
+ " (name, rolle, code_hash, code_salt, code_n, code_kennung, aktiv, erstellt)"
+ " VALUES (?,?,?,?,?,?,1,?)")
.run(r, r, hash, salt, 32768,
createHmac("sha256", sch).update(code).digest("hex"), jetzt);
codes[r] = code;
}
d.close();
function roh(pfad, host, kopf = {}, koerper = null, methode = null) {
return new Promise((fertig, schief) => {
const a = httpAnfrage({
host: "127.0.0.1", port: PORT, path: pfad,
method: methode || (koerper ? "POST" : "GET"),
headers: { Host: host, ...(koerper ? { "Content-Type": "application/json" } : {}), ...kopf },
}, (antwort) => {
let text = "";
antwort.on("data", (s) => { text += s; });
antwort.on("end", () => fertig({ code: antwort.statusCode, text, kopf: antwort.headers }));
});
a.on("error", schief);
if (koerper) a.write(JSON.stringify(koerper));
a.end();
});
}
async function anmelden(rolle, host) {
const r = await roh("/workspace/api/anmelden", host, {},
rolle === "gast" ? { rolle, code: codes[rolle], alter_ok: true } : { rolle, code: codes[rolle] });
const kekse = [].concat(r.kopf?.["set-cookie"] || []);
return { keks: kekse.map((c) => c.split(";")[0]).join("; "), code: r.code };
}
/* Jede Rolle auf der Wand, auf der sie hingehoert. */
const WAND = { admin: CREW, hand: CREW, modi: CREW, gast: CREW };
const kekse = {};
console.log("\n=== Anmeldung ===");
for (const r of ROLLEN) {
const a = await anmelden(r, WAND[r]);
kekse[r] = a.keks;
console.log(` ${r.padEnd(8)} auf ${WAND[r]} -> ${a.code}`);
}
/* ---- DogFather uebernimmt ueberall den Startkatalog ------------------ */
console.log("\n=== DogFather uebernimmt die Vorschlaege ===");
for (const b of ALLE_BEREICHE) {
const a = await roh(`/workspace/api/bereich/${b}/start`, CREW,
{ cookie: kekse.admin, origin: `https://${CREW}` }, {});
const j = JSON.parse(a.text || "{}");
console.log(` ${b.padEnd(12)} ${a.code} angelegt: ${j?.angelegt ?? "-"}`);
}
/* ---- Und jetzt: wer sieht wie viel? --------------------------------- */
console.log("\n=== Was jede Rolle danach sieht ===");
console.log(" Brett " + ROLLEN.map((r) => r.padEnd(8)).join("") + "Freigabe?");
for (const b of TREFF_BRETTER) {
const zahlen = [];
for (const r of ROLLEN) {
const a = await roh(`/workspace/api/bereich/${b}`, WAND[r], { cookie: kekse[r] });
let j = null; try { j = JSON.parse(a.text); } catch { /* keine JSON-Antwort */ }
zahlen.push(a.code === 200 ? String((j?.eintraege || []).length) : `(${a.code})`);
}
const frei = TREFF_FREIGABE_BRETTER.includes(b) ? "JA" : "-";
console.log(` ${b.padEnd(14)}` + zahlen.map((z) => z.padEnd(8)).join("") + frei);
}
console.log("\n=== Wer bekommt den Vorschlagskasten? ===");
for (const b of TREFF_BRETTER) {
const zeile = [];
for (const r of ROLLEN) {
const a = await roh(`/workspace/api/bereich/${b}/start`, WAND[r], { cookie: kekse[r] });
let j = null; try { j = JSON.parse(a.text); } catch { /* keine JSON-Antwort */ }
zeile.push(a.code === 200 ? `${(j?.vorschlaege || []).length}` : `(${a.code})`);
}
console.log(` ${b.padEnd(14)}` + zeile.map((z) => z.padEnd(8)).join(""));
}
console.log("\n=== Und die uebrigen Kategorien (ausserhalb des Rudels) ===");
const andere = Object.keys(BEREICHE).filter((b) => !TREFF_BRETTER.includes(b));
console.log(" Bereich " + ROLLEN.map((r) => r.padEnd(8)).join(""));
for (const b of andere) {
const zeile = [];
for (const r of ROLLEN) {
const a = await roh(`/workspace/api/bereich/${b}`, WAND[r], { cookie: kekse[r] });
let j = null; try { j = JSON.parse(a.text); } catch { /* keine JSON-Antwort */ }
zeile.push(a.code === 200 ? String((j?.eintraege || []).length) : `(${a.code})`);
}
console.log(` ${b.padEnd(14)}` + zeile.map((z) => z.padEnd(8)).join(""));
}
try { rmSync(ordner, { recursive: true, force: true }); } catch { /* Aufraeumrest */ }
process.exit(0);