Kalender: sechs neue Terminarten, mit zwei stillen Loechern darin
Wunsch: "kategorien wie bigmatch, turniere, Special-Live ... informier
dich was man da alles noch gebrauchen koennte und auch so dass wenn man
die sachen aussucht die ganze kachel und sachen die man eintippen muss
auch zu der jeweiligen kategorie passen."
Neu: BigMatch, Turnier, Special-Live, Collab, Raid-Train, Charity --
neben den drei internen Arten. Das Formular fragt je Art anderes:
beim BigMatch "Gegen wen?" mit 60 Minuten, beim Turnier "Welches
Turnier?" mit 120, bei Charity "Fuer wen wird gesammelt?" mit 180.
ZWEI FEHLER, DIE BEIDE NICHT ABGESTUERZT WAEREN:
1. termin_serien wurde nicht umgestellt. Die Umbauschleife laeuft ueber
zwei Tabellen, bildete den Namen der Sicherungsdatei aber ohne die
Tabelle -- und der Zeitstempel darin wird einmal pro Serverstart
gebildet. Der zweite Durchlauf wollte also dieselbe Datei anlegen,
VACUUM INTO weigerte sich, und das (richtige) "ohne Sicherung kein
Umbau" beendete die ganze Schleife. Ergebnis: termine umgestellt,
termin_serien nicht. Eine wiederkehrende BigMatch-Reihe waere ohne
erkennbaren Grund abgelehnt worden.
2. Die neuen Arten waren im Kalender UNSICHTBAR. In kalender.js standen
zwei weitere Aufzaehlungen derselben Arten: `zeigen = {call, termin,
review, frist}` und die Schalterleiste. Gefiltert wird mit
`zeigen[e.art]` -- fuer 'bigmatch' ist das undefined. Anlegen ging,
der Server meldete 201, die Zeile stand in der Datenbank, und im
Kalender war sie in keiner Ansicht zu sehen. Ohne Fehler, ohne Hinweis.
Beide Listen werden jetzt aus ARTNAME abgeleitet. Und `sichtbare()`
prueft `!== false` statt auf Wahrheit: Der Vorgabewert einer
Sichtbarkeitsfrage muss "sichtbar" sein -- ein Eintrag zu viel ist
ein Schoenheitsfehler, ein fehlender ein verpasster Termin.
Gefunden hat Nummer 2 kein Test, sondern ein Bildschirmfoto: In der
Schalterleiste standen vier Arten statt zehn. Meine eigene Pruefung war
zu dem Zeitpunkt gruen -- sie hoerte beim HTTP 201 auf.
Neu: server/pruef-arten.mjs, 28 Pruefungen. Baut eine Datenbank im ALTEN
Stand nach (samt Teilnehmer, Wecker, Serie), laesst die Anwendung
darueberlaufen und zaehlt nach; haelt CHECK und Serverliste gegeneinander;
und oeffnet zuletzt einen echten Browser, um zu sehen, ob die Eintraege
auch ankommen. Gegenprobe gefahren: mit dem alten Stand meldet sie
0 von 6 sichtbar.
Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
+117
-2
@@ -764,6 +764,121 @@ function umstellungen(d) {
|
||||
geprueft hat. Deshalb wird danach nachgesehen, ob 'spicy' wirklich
|
||||
drinsteht.
|
||||
===================================================================== */
|
||||
/* =====================================================================
|
||||
MEHR TERMINARTEN (08.09.2026)
|
||||
|
||||
Wunsch Filipe: "da sollen auch noch kategorien wie bigmatch,
|
||||
turniere, special-live ... informier dich, was man da alles noch
|
||||
gebrauchen koennte."
|
||||
|
||||
Recherchiert (Streams Charts, Kick, StreamerCollabs): Was ein
|
||||
Creator-Team im Kalender wirklich unterscheidet, sind neben den
|
||||
internen Terminen die AUFTRITTE -- Wettkaempfe (BigMatch, Turnier),
|
||||
gemeinsame Formate (Collab, Raid-Train) und die grossen Ausnahmen
|
||||
(Special-Live, Charity). Genau diese sechs kommen dazu.
|
||||
|
||||
WARUM EIN TABELLENUMBAU: Die erlaubten Werte stecken in einem
|
||||
CHECK, und ein CHECK laesst sich in SQLite nicht aendern. Dieselbe
|
||||
Lage wie bei der Rolle 'spicy' -- und deshalb hier dasselbe,
|
||||
bewaehrte Verfahren: Bauplan aus sqlite_master lesen, NUR die Liste
|
||||
ersetzen, das Ergebnis pruefen, Spalten aus PRAGMA holen, Zeilen
|
||||
INNERHALB der Transaktion zaehlen, Sicherung vorher.
|
||||
|
||||
Zwei Tabellen statt einer (termine und termin_serien), deshalb
|
||||
eine Schleife -- zweimal derselbe Text waere zweimal dieselbe
|
||||
Gelegenheit, eine Stelle zu vergessen. */
|
||||
const ARTEN_NEU = "'termin','call','review','bigmatch','turnier','special','collab','raid','charity'";
|
||||
for (const tabelle of ["termine", "termin_serien"]) {
|
||||
const plan = d.prepare(
|
||||
"SELECT sql FROM sqlite_master WHERE type = 'table' AND name = ?").get(tabelle)?.sql || "";
|
||||
/* Geprueft wird die REGEL, nicht der ganze Bauplan: SQLite hebt ihn
|
||||
woertlich auf, samt Kommentaren -- ein erklaerender Satz mit dem
|
||||
Wort 'bigmatch' wuerde sonst genuegen, damit die Umstellung sich
|
||||
fuer erledigt haelt. Genau dieser Fehler ist bei 'spicy' passiert. */
|
||||
const artRegel = plan.match(/art\s+IN\s*\(([^)]*)\)/i)?.[1] || "";
|
||||
if (!plan || !artRegel || artRegel.includes("'bigmatch'")) continue;
|
||||
|
||||
/* DER TABELLENNAME GEHOERT IN DEN DATEINAMEN (08.09.2026).
|
||||
|
||||
Hier stand `.vor-arten-${jetztStempel}` -- ohne die Tabelle. Der
|
||||
Stempel wird EINMAL pro Serverstart gebildet, diese Schleife
|
||||
laeuft aber ZWEIMAL. Der zweite Durchlauf wollte also dieselbe
|
||||
Datei anlegen, `VACUUM INTO` weigert sich (die Datei ist schon
|
||||
da), und das `break` unten beendete daraufhin die ganze Schleife.
|
||||
|
||||
Ergebnis: `termine` war umgestellt, `termin_serien` NICHT. Und
|
||||
zwar still -- die Meldung ging in die Serverausgabe, die niemand
|
||||
liest. Aufgefallen waere es erst, wenn jemand eine wiederkehrende
|
||||
BigMatch-Reihe anlegt und die Datenbank sie ohne erkennbaren
|
||||
Grund ablehnt.
|
||||
|
||||
Das `break` bleibt richtig: Wenn sich keine Sicherung anlegen
|
||||
laesst, wird nicht umgebaut. Falsch war nur der Name. */
|
||||
const sicherung = `${DB_PFAD}.vor-arten-${tabelle}-${jetztStempel}`;
|
||||
try {
|
||||
d.exec(`VACUUM INTO '${sicherung.replace(/'/g, "''")}'`);
|
||||
console.log("[workspace] Sicherung vor der Artenumstellung:", sicherung);
|
||||
} catch (fehler) {
|
||||
console.error("[workspace] Sicherung fehlgeschlagen, Artenumstellung abgebrochen:",
|
||||
fehler?.message);
|
||||
break;
|
||||
}
|
||||
|
||||
const neuerPlan = plan
|
||||
/* DAS MUSTER WIRD ZUSAMMENGESETZT, NICHT IN EINEN TEMPLATE-STRING
|
||||
GESCHRIEBEN. Dort wird \s beim Einlesen zu einem blossen "s" --
|
||||
aus "CREATE TABLE\s+" wuerde "CREATE TABLEs+", das Muster
|
||||
passte auf nichts, und die Umstellung waere STILL ausgeblieben.
|
||||
Genau so stand es hier beim ersten Anlauf; nachgemessen mit
|
||||
einem Einzeiler, der beide Schreibweisen gegen den echten
|
||||
Bauplan haelt. */
|
||||
.replace(new RegExp(
|
||||
"CREATE TABLE\\s+(?:IF\\s+NOT\\s+EXISTS\\s+)?[\"'`]?" + tabelle + "[\"'`]?", "i"),
|
||||
`CREATE TABLE ${tabelle}_neu`)
|
||||
.replace(/art\s+IN\s*\([^)]*\)/i, `art IN (${ARTEN_NEU})`);
|
||||
if (!neuerPlan.includes("'bigmatch'") || !neuerPlan.includes(`${tabelle}_neu`)) {
|
||||
console.error(`[workspace] Artenumstellung abgebrochen: Bauplan von ${tabelle} `
|
||||
+ "liess sich nicht umschreiben.");
|
||||
continue;
|
||||
}
|
||||
|
||||
const spalten = d.prepare(`PRAGMA table_info(${tabelle})`).all().map((z) => z.name);
|
||||
if (!spalten.length) continue;
|
||||
const liste = spalten.map((n) => `"${n}"`).join(", ");
|
||||
|
||||
d.exec("PRAGMA foreign_keys = OFF");
|
||||
try {
|
||||
const vorher = d.prepare(`SELECT COUNT(*) AS n FROM ${tabelle}`).get().n;
|
||||
d.exec("BEGIN");
|
||||
d.exec(neuerPlan);
|
||||
d.exec(`INSERT INTO ${tabelle}_neu (${liste}) SELECT ${liste} FROM ${tabelle};`);
|
||||
const nachher = d.prepare(`SELECT COUNT(*) AS n FROM ${tabelle}_neu`).get().n;
|
||||
if (nachher !== vorher) {
|
||||
d.exec("ROLLBACK");
|
||||
console.error(`[workspace] Artenumstellung abgebrochen: ${vorher} Zeilen vorher, `
|
||||
+ `${nachher} nachher. Sicherung: ${sicherung}`);
|
||||
} else {
|
||||
d.exec(`DROP TABLE ${tabelle};`);
|
||||
d.exec(`ALTER TABLE ${tabelle}_neu RENAME TO ${tabelle};`);
|
||||
d.exec("COMMIT");
|
||||
const kaputt = d.prepare("PRAGMA foreign_key_check").all();
|
||||
if (kaputt.length) {
|
||||
console.error("[workspace] ACHTUNG: nach der Artenumstellung", kaputt.length,
|
||||
"verwaiste Verweise. Sicherung:", sicherung);
|
||||
} else {
|
||||
console.log(`[workspace] Terminarten erweitert in ${tabelle}: ${nachher} Zeilen, `
|
||||
+ `${spalten.length} Spalten uebernommen, Verweise geprueft.`);
|
||||
}
|
||||
}
|
||||
} catch (fehler) {
|
||||
try { d.exec("ROLLBACK"); } catch { /* schon zurueckgerollt */ }
|
||||
console.error("[workspace] Artenumstellung fehlgeschlagen:", fehler?.message,
|
||||
"-- Sicherung:", sicherung);
|
||||
} finally {
|
||||
d.exec("PRAGMA foreign_keys = ON");
|
||||
}
|
||||
}
|
||||
|
||||
const rollenPlan = d.prepare(
|
||||
"SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'personen'").get()?.sql || "";
|
||||
/* GEPRUEFT WIRD DIE REGEL, NICHT DER TEXT (07.09.2026).
|
||||
@@ -1135,7 +1250,7 @@ export function db() {
|
||||
titel TEXT NOT NULL,
|
||||
beschreibung TEXT,
|
||||
art TEXT NOT NULL DEFAULT 'termin'
|
||||
CHECK (art IN ('termin','call','review')),
|
||||
CHECK (art IN ('termin','call','review','bigmatch','turnier','special','collab','raid','charity')),
|
||||
beginn TEXT NOT NULL,
|
||||
dauer_min INTEGER NOT NULL DEFAULT 30,
|
||||
ort TEXT,
|
||||
@@ -1261,7 +1376,7 @@ export function db() {
|
||||
titel TEXT NOT NULL,
|
||||
beschreibung TEXT,
|
||||
art TEXT NOT NULL DEFAULT 'termin'
|
||||
CHECK (art IN ('termin','call','review')),
|
||||
CHECK (art IN ('termin','call','review','bigmatch','turnier','special','collab','raid','charity')),
|
||||
takt TEXT NOT NULL
|
||||
CHECK (takt IN ('taeglich','werktags','woechentlich',
|
||||
'zweiwoechentlich','monatlich_datum',
|
||||
|
||||
Reference in New Issue
Block a user