Datum: der Tag kommt aus der Ortszeit, nicht aus UTC
GEFUNDEN UM 01:22, von pruef-kreislauf -- und nur, weil nachts
gearbeitet wurde.
Die Pruefung legt einen Wunsch mit dem HEUTIGEN Datum an und macht
daraus einen Termin. Gemessen:
geschickt: datum = 2026-10-01 (heuteLokal auf dem Server)
gespeichert: datum = 2026-09-30
Der Termin lag also in der Vergangenheit. Auf „Was ansteht" sortiert
er sich damit in den Abschnitt „Vorbei" ein -- und der ist mit
Absicht zugeklappt. Beim Wunsch stand „Daraus wurde ein Termin", auf
dem Brett war er nicht zu sehen. Zwei Stunden jede Nacht (im Winter
eine), genau in den Stunden, in denen hier gearbeitet wird.
URSACHE
const jetzt = () => new Date().toISOString(); // UTC
... jetzt().slice(0, 10) ... // UTC-Tag
ES WAR NICHT EINE STELLE. Nachgemessen: SECHZEHN in vierzehn Modulen,
davon ZEHN, die den falschen Tag in die Datenbank schreiben --
Termine, Wuensche, Highlights, Talente, Leads, Videos, Vorlagen --
und sechs, die „heute" vergleichen (ueberfaellige Aufgaben, Berichte,
die Frist einer Entwicklungsaufgabe).
NICHT ANGEFASST, WEIL RICHTIG: Rechnungen auf einem Datumstext mit
fester Uhrzeit (`Date.parse(tag + "T12:00:00Z") + n * 86400000`). Die
bleiben in jeder Zeitzone am selben Kalendertag -- kalender, teamlage
und serien machen es so, und das bleibt.
WARUM ES NIEMAND GEMERKT HAT
pruef-struktur sucht dieses Muster seit dem 06.09.2026. Aber:
- sie sah NUR in die `pruef-*.mjs`, nie in die Anwendung
- sie kannte die Schreibweise ueber eine FUNKTION nicht
(`const jetzt = () => ...` statt `const jetzt = ...`)
Die Wache stand vor den Pruefungen, nicht vor dem Haus -- derselbe
Fehler wie heute Nacht bei den Messports: eine Sicherung, die nur die
halbe Menge kennt, faellt in der anderen Haelfte aus, und zwar
lautlos, denn sie meldet ja „nichts gefunden".
Jetzt sieht sie in beides und kennt beide Schreibweisen. Beim ersten
scharfen Lauf fand sie sofort 23 weitere Stellen in den Pruefdateien
selbst -- dieselben Zeitbomben, gegen die sie gebaut worden war.
EINE ZWEITE WACHE, WEIL ICH SELBST HINEINGELAUFEN BIN
Mein Umbauwerkzeug hat in elf Modulen `heuteLokal()` eingesetzt und
die Einfuhr weggelassen: Es hat erst ersetzt und DANN gefragt, ob der
Name schon in der Datei steht -- da stand er, mein eigener Aufruf.
`node --check` sagt dazu nichts, „Laedt jedes Server-Modul?" auch
nicht: Die Datei ist syntaktisch tadellos. Erst der Aufruf faellt um
mit `ReferenceError: heuteLokal is not defined`. Gefunden hat es
pruef-video, zufaellig. Die anderen zehn waeren durchgerutscht.
Deshalb neu: „Ruft ein Modul etwas, das es nie eingefuehrt hat?" --
die Namen des Hauses aus den export-Zeilen gelesen, nicht
aufgezaehlt. 460 Aufrufe in 350 Dateien, alle mit Einfuhr.
pruef-kreislauf STELLT JETZT DIE RICHTIGE FRAGE
Sie war rot und hat den Fehler dabei nur gestreift: „`.kette` wird
nicht sichtbar", Zeitsperre nach 15 s. Das klingt nach der Anzeige
und schickt einen zur falschen Stelle. Neu:
- eine Zeile fragt das DATUM (ohne Browser, nennt den Fehler beim
Namen)
- der Browserteil klappt zu, was zu ist, und misst dann die Kette;
„gar nicht da" wird von „da und unsichtbar" unterschieden
NEBENBEFUND IN pruef-ics
Die Probe „fast richtig" war `echt.slice(0, -1) + "A"`. Der
Schluessel ist base64url; sein letztes Zeichen ist eines von
sechzehn. Endet er auf „A", IST die Probe der echte Schluessel, der
Server antwortet zu Recht mit 200, und die Pruefung meldet ein Loch,
das es nicht gibt -- einmal je sechzehn Laeufe. Heute Nacht zweimal
hintereinander, und die Suche ging eine halbe Stunde in eine
Aenderung, die damit nichts zu tun hatte.
GEPRUEFT
pruef-struktur 44 -> 59 Pruefungen, 0 Fehler
pruef-ics 37 -> 38, 0 Fehler
pruef-kreislauf Absturz bei Nr. 17 -> 25 Pruefungen, 0 Fehler
und gruen geblieben: treff 85, arten 28, video 74, uebernahme 39,
entwicklung 79, content 45, vorlagen 24, zuteilung 75,
scout-zuteilung 37, unterstuetzung 70, aufbewahrung 45,
bewerbung 91, treff-start 42, uebergang 65, nachwuchs 262,
auskunft 46, modi-ideen 30, neue-seiten 109, spicy 85,
wege-nach-draussen 67, aufgabenbrett 49, agentur 62,
bereiche-lesend 37 -- beide Haeuser
GEGENPROBEN, DIE WIRKLICH ROT WERDEN
- den UTC-Tag im `daraus`-Weg wieder eingebaut: pruef-kreislauf
meldet „er liegt HEUTE, nicht gestern (2026-09-30, heute ist
2026-10-01)", 25 Pruefungen, 1 Fehler -- und der Browserteil
bleibt gruen, weil er jetzt aufklappt. Jede Frage bei ihrer
eigenen Pruefung.
- eine Einfuhr aus workspace-video.js entfernt: die neue Wache
meldet „workspace-video.js: heuteLokal() (aus helfer-tag.mjs)"
- beide Erkennungen je gegen einen gebauten Rueckschritt geprueft
(Funktion, Variable, zwei Schritte, Date.now-Rechnung) und gegen
das, was NICHT anschlagen darf (UTC-Mittag, voller Zeitstempel,
fremdes Date, Name im Kommentar, Eigenschaft am Objekt)
EIN FEHLER BEIM UMBAU, HIER FESTGEHALTEN: Mein erster Lauf ueber die
Pruefdateien hat stumpf ersetzt und dabei KOMMENTARE umgeschrieben --
in sieben Dateien stand die alte Schreibweise als Beleg in der
Begruendung, und daraus wurde das Gegenteil. Bemerkt hat es der
Vergleich der Zahlen (34 Stellen statt der gemessenen 24), nicht die
Absicht. Zurueckgenommen und mit Schutz fuer Kommentare und
Zeichenketten wiederholt.
Datenbank vorher gesichert. Keine Schemaaenderung.
Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
@@ -45,6 +45,7 @@ const express = (await import("express")).default;
|
|||||||
const ec = express.response.cookie;
|
const ec = express.response.cookie;
|
||||||
express.response.cookie = function (n, w, o) { return ec.call(this, n, w, { ...(o || {}), secure: false }); };
|
express.response.cookie = function (n, w, o) { return ec.call(this, n, w, { ...(o || {}), secure: false }); };
|
||||||
import { notbremse } from "./helfer-notbremse.mjs";
|
import { notbremse } from "./helfer-notbremse.mjs";
|
||||||
|
import { heuteLokal } from "./helfer-tag.mjs";
|
||||||
await import("./index.js");
|
await import("./index.js");
|
||||||
notbremse(180_000, "pruef-auskunft");
|
notbremse(180_000, "pruef-auskunft");
|
||||||
await new Promise((r) => setTimeout(r, 700));
|
await new Promise((r) => setTimeout(r, 700));
|
||||||
@@ -91,7 +92,7 @@ let idDogi, idRieke, idGast;
|
|||||||
treff_entfernt.autor_id (ebenfalls ohne). */
|
treff_entfernt.autor_id (ebenfalls ohne). */
|
||||||
d.prepare("INSERT INTO eintraege (bereich, art, titel, text, datum, erstellt, erstellt_von)"
|
d.prepare("INSERT INTO eintraege (bereich, art, titel, text, datum, erstellt, erstellt_von)"
|
||||||
+ " VALUES ('treff','hallo','KESSI-EINTRAG','Hallo zusammen',?,?,?)")
|
+ " VALUES ('treff','hallo','KESSI-EINTRAG','Hallo zusammen',?,?,?)")
|
||||||
.run(jetzt.slice(0, 10), jetzt, idGast);
|
.run(heuteLokal(), jetzt, idGast);
|
||||||
const raum = (() => {
|
const raum = (() => {
|
||||||
d.prepare("INSERT INTO chat_raeume (art, name, erstellt, erstellt_von) VALUES ('gruppe','Testraum',?,?)")
|
d.prepare("INSERT INTO chat_raeume (art, name, erstellt, erstellt_von) VALUES ('gruppe','Testraum',?,?)")
|
||||||
.run(jetzt, idDogi);
|
.run(jetzt, idDogi);
|
||||||
|
|||||||
+19
-1
@@ -341,10 +341,28 @@ melde("\n=== Sichtbarkeit — der Weg ohne Anmeldung darf nicht mehr zeigen ==="
|
|||||||
======================================================================= */
|
======================================================================= */
|
||||||
melde("\n=== Falsche Schluessel ===");
|
melde("\n=== Falsche Schluessel ===");
|
||||||
{
|
{
|
||||||
|
/* DIE PROBE DARF NICHT DER ECHTE SCHLUESSEL SEIN (01.10.2026).
|
||||||
|
|
||||||
|
Hier stand `echt.slice(0, -1) + "A"`. Der Schluessel ist base64url
|
||||||
|
aus 32 Bytes; sein letztes Zeichen kodiert vier Bit und ist eines
|
||||||
|
von sechzehn. Endet er auf „A", IST die Probe der echte
|
||||||
|
Schluessel -- der Server antwortet zu Recht mit 200, und diese
|
||||||
|
Pruefung meldet ein Loch, das es nicht gibt. Einmal je sechzehn
|
||||||
|
Laeufe, also mehrmals im Monat; heute Nacht zweimal
|
||||||
|
hintereinander, und die Suche ging eine halbe Stunde in eine
|
||||||
|
Aenderung, die damit nichts zu tun hatte.
|
||||||
|
|
||||||
|
Ein Fehlalarm, den man nicht nachstellen kann, ist der sicherste
|
||||||
|
Weg, eine Pruefung abzuschalten. */
|
||||||
|
const echt = String(linkLuna).split("/").pop().replace(".ics", "");
|
||||||
|
const fastRichtig = echt.slice(0, -1) + (echt.at(-1) === "A" ? "B" : "A");
|
||||||
|
ok(fastRichtig !== echt && fastRichtig.length === echt.length,
|
||||||
|
`die Probe unterscheidet sich vom echten Schluessel (…${echt.slice(-4)} gegen …${fastRichtig.slice(-4)})`);
|
||||||
|
|
||||||
const proben = [
|
const proben = [
|
||||||
["kurz", "abc"],
|
["kurz", "abc"],
|
||||||
["leer", ""],
|
["leer", ""],
|
||||||
["fast richtig", String(linkLuna).split("/").pop().replace(".ics", "").slice(0, -1) + "A"],
|
["fast richtig", fastRichtig],
|
||||||
["mit Punkten", "../../workspace/start"],
|
["mit Punkten", "../../workspace/start"],
|
||||||
["SQL-Versuch", "' OR '1'='1"],
|
["SQL-Versuch", "' OR '1'='1"],
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -149,6 +149,27 @@ let terminId = 0;
|
|||||||
ok(t?.aus?.bereich === "wunsch", `und er weiss, woher er kam (${t?.aus?.bereich})`);
|
ok(t?.aus?.bereich === "wunsch", `und er weiss, woher er kam (${t?.aus?.bereich})`);
|
||||||
ok(t?.aus?.von_name === "Lena",
|
ok(t?.aus?.von_name === "Lena",
|
||||||
`mit dem Namen dessen, der den Wunsch schrieb ("${t?.aus?.von_name}")`);
|
`mit dem Namen dessen, der den Wunsch schrieb ("${t?.aus?.von_name}")`);
|
||||||
|
|
||||||
|
/* ---- UND AN WELCHEM TAG? (01.10.2026) --------------------------
|
||||||
|
|
||||||
|
DIE FRAGE HAT HIER GEFEHLT, und der Fehler stand trotzdem vor
|
||||||
|
der Tuer: Der Termin bekam sein Datum aus `jetzt().slice(0, 10)`
|
||||||
|
-- dem UTC-Tag. Um 01:22 Ortszeit war das der 30.09., nicht der
|
||||||
|
01.10.
|
||||||
|
|
||||||
|
WAS DAS ANRICHTET: Auf „Was ansteht" sortiert sich der Termin
|
||||||
|
nach Datum in einen Zeitstrahl ein. Ein Tag in der Vergangenheit
|
||||||
|
heisst Abschnitt „Vorbei" -- und der ist mit Absicht zugeklappt.
|
||||||
|
Beim Wunsch stand „Daraus wurde ein Termin", auf dem Brett war
|
||||||
|
er nicht zu sehen. Zwei Stunden jede Nacht, genau die Stunden,
|
||||||
|
in denen hier gearbeitet wird.
|
||||||
|
|
||||||
|
GEFUNDEN HAT ES DER BROWSERTEIL weiter unten -- aber nur als
|
||||||
|
Folge („`.kette` wird nicht sichtbar"), und das schickt einen zur
|
||||||
|
falschen Stelle. Diese eine Zeile nennt den Fehler beim Namen und
|
||||||
|
braucht dafuer keinen Browser. */
|
||||||
|
ok(t?.datum === heuteLokal(),
|
||||||
|
`und er liegt HEUTE, nicht gestern (${t?.datum}, heute ist ${heuteLokal()})`);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* =======================================================================
|
/* =======================================================================
|
||||||
@@ -237,8 +258,46 @@ melde("=== 5. Was man sieht ===");
|
|||||||
const konsole = [];
|
const konsole = [];
|
||||||
seite.on("console", (e) => { if (e.type() === "error") konsole.push(e.text()); });
|
seite.on("console", (e) => { if (e.type() === "error") konsole.push(e.text()); });
|
||||||
await seite.goto(`${BASIS}/workspace/bereich.html?b=ansteht`, { waitUntil: "networkidle" });
|
await seite.goto(`${BASIS}/workspace/bereich.html?b=ansteht`, { waitUntil: "networkidle" });
|
||||||
await seite.waitForSelector(".kette", { timeout: 15_000 });
|
|
||||||
|
/* ---- ERST AUFKLAPPEN, DANN HINSEHEN (01.10.2026) -------------
|
||||||
|
|
||||||
|
Hier stand nur `waitForSelector(".kette")`. Das wartet auf
|
||||||
|
SICHTBARKEIT -- und am 01.10. um 01:22 lag der Termin wegen
|
||||||
|
eines falschen Datums im Abschnitt „Vorbei", der von sich aus
|
||||||
|
zugeklappt ist. Die Meldung lautete „Zeitsperre nach 15 s", mit
|
||||||
|
dem Zusatz „33 x locator resolved to 2 elements": Das Element
|
||||||
|
WAR da. Wer die erste Zeile liest, sucht in der Anzeige; die
|
||||||
|
Ursache lag im Datum.
|
||||||
|
|
||||||
|
Diese Pruefung misst die KETTE, nicht die Zeiteinteilung. Also
|
||||||
|
macht sie auf, was zu ist -- wie ein Mensch, der einen
|
||||||
|
Abschnitt anklickt. Dass der Tag stimmt, fragt jetzt eine
|
||||||
|
eigene Zeile weiter oben; so bleibt jede Frage bei einer
|
||||||
|
Pruefung, und ein Fehler zeigt sich dort, wo er hingehoert. */
|
||||||
|
await seite.waitForSelector(".kette", { state: "attached", timeout: 15_000 });
|
||||||
|
const aufgeklappt = await seite.evaluate(() => {
|
||||||
|
let n = 0;
|
||||||
|
for (const schild of document.querySelectorAll(".zeitstrahl__schild")) {
|
||||||
|
const kasten = schild.nextElementSibling;
|
||||||
|
if (kasten?.hidden) { schild.click(); n++; }
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
});
|
||||||
await seite.waitForTimeout(400);
|
await seite.waitForTimeout(400);
|
||||||
|
if (aufgeklappt) melde(` -- ${aufgeklappt} zugeklappte(n) Abschnitt(e) aufgemacht`);
|
||||||
|
|
||||||
|
/* DRITTER AUSGANG: „gar nicht da" ist etwas anderes als „da und
|
||||||
|
unsichtbar". Ohne diese Unterscheidung heisst beides
|
||||||
|
„Zeitsperre", und man sucht zweimal an der falschen Stelle. */
|
||||||
|
const lage = await seite.evaluate(() => {
|
||||||
|
const alle = [...document.querySelectorAll(".kette")];
|
||||||
|
return {
|
||||||
|
da: alle.length,
|
||||||
|
sichtbar: alle.filter((z) => z.getBoundingClientRect().height > 0).length,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
ok(lage.da >= 2 && lage.sichtbar === lage.da,
|
||||||
|
`beide Kettenzeilen stehen sichtbar auf der Seite (${lage.sichtbar} von ${lage.da})`);
|
||||||
|
|
||||||
const m = await seite.evaluate(() => ({
|
const m = await seite.evaluate(() => ({
|
||||||
her: [...document.querySelectorAll(".kette--her")].map((z) => z.textContent.trim()),
|
her: [...document.querySelectorAll(".kette--her")].map((z) => z.textContent.trim()),
|
||||||
|
|||||||
@@ -80,12 +80,12 @@ console.log("\n=== 1. Eine bestehende Datenbank ohne den neuen Bereich ===\n");
|
|||||||
);`);
|
);`);
|
||||||
for (let i = 1; i <= 7; i++) {
|
for (let i = 1; i <= 7; i++) {
|
||||||
d.prepare("INSERT INTO eintraege (bereich, art, titel, datum, erstellt) VALUES (?,?,?,?,?)")
|
d.prepare("INSERT INTO eintraege (bereich, art, titel, datum, erstellt) VALUES (?,?,?,?,?)")
|
||||||
.run("live", "vorbereitung", `Altbestand ${i}`, jetzt.slice(0, 10), jetzt);
|
.run("live", "vorbereitung", `Altbestand ${i}`, heuteLokal(), jetzt);
|
||||||
}
|
}
|
||||||
const abgelehnt = (() => {
|
const abgelehnt = (() => {
|
||||||
try {
|
try {
|
||||||
d.prepare("INSERT INTO eintraege (bereich, art, titel, datum, erstellt) VALUES (?,?,?,?,?)")
|
d.prepare("INSERT INTO eintraege (bereich, art, titel, datum, erstellt) VALUES (?,?,?,?,?)")
|
||||||
.run("ideen", "content", "geht noch nicht", jetzt.slice(0, 10), jetzt);
|
.run("ideen", "content", "geht noch nicht", heuteLokal(), jetzt);
|
||||||
return false;
|
return false;
|
||||||
} catch { return true; }
|
} catch { return true; }
|
||||||
})();
|
})();
|
||||||
@@ -103,6 +103,7 @@ const ec = express.response.cookie;
|
|||||||
express.response.cookie = function (n, w, o) { return ec.call(this, n, w, { ...(o || {}), secure: false }); };
|
express.response.cookie = function (n, w, o) { return ec.call(this, n, w, { ...(o || {}), secure: false }); };
|
||||||
import { notbremse } from "./helfer-notbremse.mjs";
|
import { notbremse } from "./helfer-notbremse.mjs";
|
||||||
import { eigenerPort } from "./helfer-port.mjs";
|
import { eigenerPort } from "./helfer-port.mjs";
|
||||||
|
import { heuteLokal } from "./helfer-tag.mjs";
|
||||||
await import("./index.js");
|
await import("./index.js");
|
||||||
notbremse(180_000, "pruef-modi-ideen");
|
notbremse(180_000, "pruef-modi-ideen");
|
||||||
await new Promise((r) => setTimeout(r, 900));
|
await new Promise((r) => setTimeout(r, 900));
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ const express = (await import("express")).default;
|
|||||||
const ec = express.response.cookie;
|
const ec = express.response.cookie;
|
||||||
express.response.cookie = function (n, w, o) { return ec.call(this, n, w, { ...(o || {}), secure: false }); };
|
express.response.cookie = function (n, w, o) { return ec.call(this, n, w, { ...(o || {}), secure: false }); };
|
||||||
import { notbremse } from "./helfer-notbremse.mjs";
|
import { notbremse } from "./helfer-notbremse.mjs";
|
||||||
|
import { heuteLokal } from "./helfer-tag.mjs";
|
||||||
await import("./index.js");
|
await import("./index.js");
|
||||||
notbremse(240_000, "pruef-nachwuchs");
|
notbremse(240_000, "pruef-nachwuchs");
|
||||||
await new Promise((r) => setTimeout(r, 700));
|
await new Promise((r) => setTimeout(r, 700));
|
||||||
@@ -106,7 +107,7 @@ anlegen("Mara", "linke", "CODE-LINK-0001");
|
|||||||
Trichter ein gruener Haken ueber der Null. */
|
Trichter ein gruener Haken ueber der Null. */
|
||||||
d.prepare("INSERT INTO eintraege (bereich, art, titel, text, datum, erstellt, erstellt_von, einsatz)"
|
d.prepare("INSERT INTO eintraege (bereich, art, titel, text, datum, erstellt, erstellt_von, einsatz)"
|
||||||
+ " VALUES ('talente','ruhig','Kessi aus dem Chat','Faellt seit Wochen auf.',?,?,?,?)")
|
+ " VALUES ('talente','ruhig','Kessi aus dem Chat','Faellt seit Wochen auf.',?,?,?,?)")
|
||||||
.run(jetzt.slice(0, 10), jetzt, idDogi, "Im Stream am Dienstag");
|
.run(heuteLokal(), jetzt, idDogi, "Im Stream am Dienstag");
|
||||||
const idTalent = d.prepare("SELECT last_insert_rowid() AS id").get().id;
|
const idTalent = d.prepare("SELECT last_insert_rowid() AS id").get().id;
|
||||||
d.close();
|
d.close();
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ const express = (await import("express")).default;
|
|||||||
const ec = express.response.cookie;
|
const ec = express.response.cookie;
|
||||||
express.response.cookie = function (n, w, o) { return ec.call(this, n, w, { ...(o || {}), secure: false }); };
|
express.response.cookie = function (n, w, o) { return ec.call(this, n, w, { ...(o || {}), secure: false }); };
|
||||||
import { notbremse } from "./helfer-notbremse.mjs";
|
import { notbremse } from "./helfer-notbremse.mjs";
|
||||||
|
import { heuteLokal } from "./helfer-tag.mjs";
|
||||||
await import("./index.js");
|
await import("./index.js");
|
||||||
notbremse(240_000, "pruef-neue-seiten");
|
notbremse(240_000, "pruef-neue-seiten");
|
||||||
await new Promise((r) => setTimeout(r, 700));
|
await new Promise((r) => setTimeout(r, 700));
|
||||||
@@ -87,7 +88,7 @@ const idKessi = anlegen("Kessi", "gast", "CODE-GAST-0001", ALT);
|
|||||||
eine Meldung und eine Maßnahme gibt. */
|
eine Meldung und eine Maßnahme gibt. */
|
||||||
d.prepare("INSERT INTO eintraege (bereich, art, titel, text, datum, erstellt, erstellt_von)"
|
d.prepare("INSERT INTO eintraege (bereich, art, titel, text, datum, erstellt, erstellt_von)"
|
||||||
+ " VALUES ('treff','hallo','Hallo, ich bin die Kessi','Freue mich, hier zu sein!',?,?,?)")
|
+ " VALUES ('treff','hallo','Hallo, ich bin die Kessi','Freue mich, hier zu sein!',?,?,?)")
|
||||||
.run(jetzt.slice(0, 10), jetzt, idKessi);
|
.run(heuteLokal(), jetzt, idKessi);
|
||||||
const beitrag = d.prepare("SELECT last_insert_rowid() AS id").get().id;
|
const beitrag = d.prepare("SELECT last_insert_rowid() AS id").get().id;
|
||||||
d.close();
|
d.close();
|
||||||
|
|
||||||
@@ -156,7 +157,7 @@ let idHand = null;
|
|||||||
const talent = (titel, text) => {
|
const talent = (titel, text) => {
|
||||||
dd.prepare("INSERT INTO eintraege (bereich, art, titel, text, datum, erstellt, erstellt_von, einsatz)"
|
dd.prepare("INSERT INTO eintraege (bereich, art, titel, text, datum, erstellt, erstellt_von, einsatz)"
|
||||||
+ " VALUES ('talente','ruhig',?,?,?,?,?,?)")
|
+ " VALUES ('talente','ruhig',?,?,?,?,?,?)")
|
||||||
.run(titel, text, jetzt.slice(0, 10), jetzt, idDogi, "Im Stream am Dienstag");
|
.run(titel, text, heuteLokal(), jetzt, idDogi, "Im Stream am Dienstag");
|
||||||
return dd.prepare("SELECT last_insert_rowid() AS id").get().id;
|
return dd.prepare("SELECT last_insert_rowid() AS id").get().id;
|
||||||
};
|
};
|
||||||
talent("Kessi aus dem Chat", "Faellt seit Wochen auf.");
|
talent("Kessi aus dem Chat", "Faellt seit Wochen auf.");
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ import { spawn } from "node:child_process";
|
|||||||
import { DatabaseSync } from "node:sqlite";
|
import { DatabaseSync } from "node:sqlite";
|
||||||
import { scryptSync, randomBytes } from "node:crypto";
|
import { scryptSync, randomBytes } from "node:crypto";
|
||||||
import { notbremse } from "./helfer-notbremse.mjs";
|
import { notbremse } from "./helfer-notbremse.mjs";
|
||||||
|
import { heuteLokal } from "./helfer-tag.mjs";
|
||||||
|
|
||||||
notbremse(300_000, "die Spicy-Pruefung");
|
notbremse(300_000, "die Spicy-Pruefung");
|
||||||
|
|
||||||
@@ -137,7 +138,7 @@ let idDogi, idMax, idLuna, spaltenVorher, personenVorher;
|
|||||||
.run(idLuna, idMax, jetzt);
|
.run(idLuna, idMax, jetzt);
|
||||||
d.prepare(`INSERT INTO eintraege (bereich, art, titel, datum, creator_id, erstellt, erstellt_von)
|
d.prepare(`INSERT INTO eintraege (bereich, art, titel, datum, creator_id, erstellt, erstellt_von)
|
||||||
VALUES ('technik','problem','Ton bricht ab',?,?,?,?)`)
|
VALUES ('technik','problem','Ton bricht ab',?,?,?,?)`)
|
||||||
.run(jetzt.slice(0, 10), idLuna, jetzt, idMax);
|
.run(heuteLokal(), idLuna, jetzt, idMax);
|
||||||
|
|
||||||
spaltenVorher = d.prepare("PRAGMA table_info(personen)").all().map((z) => z.name);
|
spaltenVorher = d.prepare("PRAGMA table_info(personen)").all().map((z) => z.name);
|
||||||
personenVorher = d.prepare("SELECT COUNT(*) AS n FROM personen").get().n;
|
personenVorher = d.prepare("SELECT COUNT(*) AS n FROM personen").get().n;
|
||||||
|
|||||||
+238
-49
@@ -772,74 +772,263 @@ console.log(`\n=== Laedt jedes Server-Modul? ===`);
|
|||||||
Deshalb wird es hier gesucht, statt darauf zu warten, dass es wieder
|
Deshalb wird es hier gesucht, statt darauf zu warten, dass es wieder
|
||||||
jemanden trifft. Gemeint ist nur das TAGESDATUM; ein Zeitstempel
|
jemanden trifft. Gemeint ist nur das TAGESDATUM; ein Zeitstempel
|
||||||
(`erstellt`) darf und soll UTC sein. */
|
(`erstellt`) darf und soll UTC sein. */
|
||||||
console.log(`\n=== Rechnen die Pruefungen mit Ortszeit? ===`);
|
console.log(`\n=== Ruft ein Modul etwas, das es nie eingefuehrt hat? ===`);
|
||||||
|
/* ===================================================================
|
||||||
|
AM 01.10.2026 SELBST GEBAUT UND FAST AUSGELIEFERT.
|
||||||
|
|
||||||
|
Ein Werkzeug von mir hat in elf Modulen `heuteLokal()` eingesetzt
|
||||||
|
und die Einfuhr weggelassen. `node --check` sagt dazu nichts, und
|
||||||
|
„Laedt jedes Server-Modul?" ein Stueck weiter oben auch nicht: Die
|
||||||
|
Datei ist syntaktisch tadellos. Erst der AUFRUF faellt um:
|
||||||
|
|
||||||
|
ReferenceError: heuteLokal is not defined
|
||||||
|
|
||||||
|
Gefunden hat es pruef-video -- zufaellig, weil dort genau diese
|
||||||
|
Zeile geprueft wird. Die anderen zehn Module waeren durchgerutscht,
|
||||||
|
und bei einer Zeile, die nur nachts laeuft, faellt das erst Wochen
|
||||||
|
spaeter jemandem auf.
|
||||||
|
|
||||||
|
DAS IST EINE DRITTE SORTE FEHLER an dieser Stelle: nicht „die Datei
|
||||||
|
ist kaputt" und nicht „die Datei tut das Falsche", sondern „die
|
||||||
|
Datei faellt erst um, wenn jemand genau diese Zeile braucht".
|
||||||
|
|
||||||
|
ABGELEITET, NICHT AUFGEZAEHLT: Die Namen des Hauses kommen aus den
|
||||||
|
`export`-Zeilen von workspace.js und der helfer-Module. Eine
|
||||||
|
gepflegte Liste waere hier genau die, die beim naechsten Export
|
||||||
|
nicht mitwaechst -- derselbe Fehler, an dem dieses Haus schon
|
||||||
|
viermal haengengeblieben ist.
|
||||||
|
=================================================================== */
|
||||||
{
|
{
|
||||||
const dateien = readdirSync(SERVER).filter((n) => n.startsWith("pruef-") && n.endsWith(".mjs"));
|
/** Kommentare und Zeichenketten weg, Zeilen behalten. Sonst zaehlt
|
||||||
ok(dateien.length >= 30, `${dateien.length} Pruefdateien durchgesehen`);
|
* ein Name in einem SQL-Text oder in einer Begruendung als Aufruf. */
|
||||||
|
const nurCode = (text) => text
|
||||||
|
.replace(/\/\*[\s\S]*?\*\//g, (m) => m.replace(/[^\n]/g, " "))
|
||||||
|
.replace(/^\s*\/\/.*$/gm, "")
|
||||||
|
.replace(/`(?:[^`\\]|\\.)*`/g, (m) => m.replace(/[^\n]/g, " "))
|
||||||
|
.replace(/"(?:[^"\\\n]|\\.)*"/g, "\"\"")
|
||||||
|
.replace(/'(?:[^'\\\n]|\\.)*'/g, "''");
|
||||||
|
|
||||||
|
/** Was eine Datei nach aussen gibt -- aus ihren eigenen Zeilen. */
|
||||||
|
const exporte = (text) => {
|
||||||
|
const raus = new Set();
|
||||||
|
for (const t of text.matchAll(
|
||||||
|
/^export\s+(?:async\s+)?(?:function|const|let|class)\s+(\w+)/gm)) raus.add(t[1]);
|
||||||
|
return raus;
|
||||||
|
};
|
||||||
|
|
||||||
|
const quellen = ["workspace.js", "helfer-zeit.mjs", "helfer-tag.mjs"];
|
||||||
|
const hausNamen = new Map(); // Name -> woher
|
||||||
|
for (const q of quellen) {
|
||||||
|
for (const n of exporte(readFileSync(join(SERVER, q), "utf8"))) hausNamen.set(n, q);
|
||||||
|
}
|
||||||
|
ok(hausNamen.size >= 30,
|
||||||
|
`${hausNamen.size} ausgeleitete Namen aus ${quellen.length} Quellen gelesen`);
|
||||||
|
|
||||||
|
/** Welche Namen kennt diese Datei? Eingefuehrte, selbst erklaerte
|
||||||
|
* und aus einer Zerlegung entnommene -- alles, was nicht zu einem
|
||||||
|
* ReferenceError fuehren kann. */
|
||||||
|
const bekannt = (code) => {
|
||||||
|
const kennt = new Set();
|
||||||
|
for (const t of code.matchAll(/import\s*\{([^}]*)\}\s*from/g)) {
|
||||||
|
for (const stueck of t[1].split(",")) {
|
||||||
|
const n = stueck.trim().split(/\s+as\s+/).pop().trim();
|
||||||
|
if (n) kennt.add(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const t of code.matchAll(/(?:const|let|var)\s*\{([^}]*)\}\s*=/g)) {
|
||||||
|
for (const stueck of t[1].split(",")) {
|
||||||
|
const n = stueck.trim().split(":").pop().trim();
|
||||||
|
if (n) kennt.add(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const t of code.matchAll(
|
||||||
|
/(?:^|\s)(?:const|let|var|function|class)\s+(\w+)/g)) kennt.add(t[1]);
|
||||||
|
for (const t of code.matchAll(/import\s+(\w+)\s+from/g)) kennt.add(t[1]);
|
||||||
|
return kennt;
|
||||||
|
};
|
||||||
|
|
||||||
|
const dateien = readdirSync(SERVER)
|
||||||
|
.filter((n) => (n.endsWith(".js") || n.endsWith(".mjs")) && !quellen.includes(n));
|
||||||
|
const fehlt = [];
|
||||||
|
let gesucht = 0;
|
||||||
|
for (const datei of dateien) {
|
||||||
|
if (datei === "pruef-struktur.mjs") continue; /* siehe Gegenprobe */
|
||||||
|
const code = nurCode(readFileSync(join(SERVER, datei), "utf8"));
|
||||||
|
const kennt = bekannt(code);
|
||||||
|
for (const [name, woher] of hausNamen) {
|
||||||
|
/* Nur ein AUFRUF zaehlt. Ein Name in einer Eigenschaft
|
||||||
|
(`x.heuteLokal`) ist etwas anderes und gehoert nicht hierher. */
|
||||||
|
const ruft = new RegExp(`(^|[^\\w.])${name}\\s*\\(`, "m").test(code);
|
||||||
|
if (!ruft) continue;
|
||||||
|
gesucht++;
|
||||||
|
if (!kennt.has(name)) fehlt.push(`${datei}: ${name}() (aus ${woher})`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ok(gesucht > 50, `${gesucht} Aufrufe von Hausnamen in ${dateien.length} Dateien angesehen`);
|
||||||
|
ok(fehlt.length === 0,
|
||||||
|
fehlt.length
|
||||||
|
? `rufen etwas, das sie nicht eingefuehrt haben — das faellt erst beim`
|
||||||
|
+ ` Aufruf um, nicht beim Laden:\n ` + fehlt.slice(0, 12).join("\n ")
|
||||||
|
: "jeder Aufruf eines Hausnamens hat auch seine Einfuhr");
|
||||||
|
|
||||||
|
/* ---- GEGENPROBEN --------------------------------------------------
|
||||||
|
Die Zeile darueber meldet „in Ordnung", solange sie nichts findet.
|
||||||
|
Heute Nacht haette sie elf Dateien gefunden -- also einmal zeigen,
|
||||||
|
dass sie das auch kann. */
|
||||||
|
{
|
||||||
|
const probeFehlt = (code, name) => {
|
||||||
|
const c = nurCode(code);
|
||||||
|
const ruft = new RegExp(`(^|[^\\w.])${name}\\s*\\(`, "m").test(c);
|
||||||
|
return ruft && !bekannt(c).has(name);
|
||||||
|
};
|
||||||
|
ok(probeFehlt('const t = heuteLokal();', "heuteLokal"),
|
||||||
|
"Gegenprobe: ein Aufruf ohne Einfuhr faellt auf");
|
||||||
|
ok(!probeFehlt('import { heuteLokal } from "./workspace.js";\nconst t = heuteLokal();',
|
||||||
|
"heuteLokal"), " mit Einfuhr NICHT");
|
||||||
|
ok(!probeFehlt('const { heuteLokal } = await import("./workspace.js");\n'
|
||||||
|
+ 'const t = heuteLokal();', "heuteLokal"), " und ueber eine Zerlegung auch nicht");
|
||||||
|
ok(!probeFehlt('function heuteLokal() { return 1; }\nconst t = heuteLokal();',
|
||||||
|
"heuteLokal"), " wer ihn selbst erklaert, ebenfalls nicht");
|
||||||
|
ok(!probeFehlt('/* heuteLokal() waere hier falsch */\nconst t = 1;', "heuteLokal"),
|
||||||
|
" und ein Name im Kommentar ist kein Aufruf");
|
||||||
|
ok(!probeFehlt('const t = uhr.heuteLokal();', "heuteLokal"),
|
||||||
|
" eine Eigenschaft an einem Objekt auch nicht");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`\n=== Wird der TAG in Ortszeit gebildet -- ueberall? ===`);
|
||||||
|
/* ===================================================================
|
||||||
|
AM 01.10.2026 UM 01:22 GEWACHSEN, weil diese Wache versagt hatte.
|
||||||
|
|
||||||
|
Sie sah seit dem 06.09. nur in die `pruef-*.mjs`. In der ANWENDUNG
|
||||||
|
standen zur selben Zeit SECHZEHN Stellen, die einen Kalendertag aus
|
||||||
|
UTC bilden -- zehn davon schrieben ihn in die Datenbank.
|
||||||
|
|
||||||
|
Aufgefallen ist es nicht hier, sondern in pruef-kreislauf: Ein
|
||||||
|
Wunsch mit dem heutigen Datum wurde zu einem Termin, und der trug
|
||||||
|
`2026-09-30` statt `2026-10-01`. Auf dem Brett „Was ansteht" landete
|
||||||
|
er damit unter „Vorbei" -- einem Abschnitt, der von sich aus
|
||||||
|
zugeklappt ist. Der Termin war da und war nicht zu sehen.
|
||||||
|
|
||||||
|
Eine Sicherung, die nur die halbe Menge kennt, faellt in der
|
||||||
|
anderen Haelfte aus -- lautlos, denn sie meldet ja „nichts
|
||||||
|
gefunden". Deshalb sieht sie jetzt in BEIDES: in die Anwendung und
|
||||||
|
in die Pruefungen.
|
||||||
|
=================================================================== */
|
||||||
|
{
|
||||||
|
const pruefungen = readdirSync(SERVER)
|
||||||
|
.filter((n) => (n.startsWith("pruef-") || n.startsWith("mess-")) && n.endsWith(".mjs"));
|
||||||
|
/* DIE ANWENDUNG -- abgeleitet, nicht aufgezaehlt: alles, was der
|
||||||
|
Dienst laedt, liegt als `.js` im Serverordner. Eine Liste von
|
||||||
|
Dateinamen waere die naechste, die beim uebernaechsten Modul
|
||||||
|
nicht mitwaechst. */
|
||||||
|
const anwendung = readdirSync(SERVER).filter((n) => n.endsWith(".js"));
|
||||||
|
const dateien = [...anwendung, ...pruefungen];
|
||||||
|
ok(anwendung.length >= 30 && pruefungen.length >= 30,
|
||||||
|
`${anwendung.length} Dateien der Anwendung und ${pruefungen.length} Pruef-/Messdateien durchgesehen`);
|
||||||
|
|
||||||
|
/* EINE UHRZEIT IM AUSDRUCK HEISST: DER TAG STEHT SCHON FEST.
|
||||||
|
`Date.parse(tag + "T12:00:00Z") + n * 86400000` bleibt in jeder
|
||||||
|
Zeitzone am selben Kalendertag -- das ist der dokumentierte Weg
|
||||||
|
des Hauses (workspace-kalender, workspace-teamlage,
|
||||||
|
workspace-serien). Erkannt wird das am Ausdruck selbst; eine
|
||||||
|
Liste erlaubter Ausnahmen braucht es dadurch nicht, und eine
|
||||||
|
Liste, die niemand pflegt, waere die naechste Stelle, an der es
|
||||||
|
auseinanderlaeuft. */
|
||||||
|
const festeUhrzeit = /T\d{2}:\d{2}:\d{2}Z/;
|
||||||
|
|
||||||
|
/** Alle Stellen einer Datei, an denen aus einem ZEITPUNKT ein
|
||||||
|
* Kalendertag wird. Gibt Zeilennummern zurueck. */
|
||||||
|
function utcTage(text) {
|
||||||
|
const treffer = [];
|
||||||
|
const zeile = (i) => text.slice(0, i).split("\n").length;
|
||||||
|
|
||||||
|
/* (1) Direkt: new Date(...).toISOString().slice(0, 10) */
|
||||||
|
for (const t of text.matchAll(
|
||||||
|
/new Date\(([^;]*?)\)\s*\.\s*toISOString\(\)\s*\.\s*slice\(\s*0\s*,\s*10\s*\)/g)) {
|
||||||
|
if (festeUhrzeit.test(t[1])) continue;
|
||||||
|
treffer.push(zeile(t.index));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (2) Ueber einen NAMEN. Zuerst sammeln, welche Namen einen
|
||||||
|
UTC-Zeitstempel liefern -- als Funktion ODER als Wert. Genau
|
||||||
|
diese Schreibweise fehlte bis heute:
|
||||||
|
|
||||||
|
const jetzt = () => new Date().toISOString();
|
||||||
|
... jetzt().slice(0, 10) ...
|
||||||
|
|
||||||
|
Und in zwei Schritten kommt sie auch vor:
|
||||||
|
|
||||||
|
const jetztIso = jetzt();
|
||||||
|
... jetztIso.slice(0, 10) ... */
|
||||||
|
const utcNamen = new Set();
|
||||||
|
for (const t of text.matchAll(
|
||||||
|
/(?:const|let)\s+(\w+)\s*=\s*(?:\(\)\s*=>\s*)?new Date\(\)\.toISOString\(\)/g)) {
|
||||||
|
utcNamen.add(t[1]);
|
||||||
|
}
|
||||||
|
for (let runde = 0; runde < 2; runde++) {
|
||||||
|
for (const t of text.matchAll(/(?:const|let)\s+(\w+)\s*=\s*(\w+)\(\)\s*;/g)) {
|
||||||
|
if (utcNamen.has(t[2])) utcNamen.add(t[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const t of text.matchAll(/(\w+)(\(\))?\s*\.\s*slice\(\s*0\s*,\s*10\s*\)/g)) {
|
||||||
|
if (utcNamen.has(t[1])) treffer.push(zeile(t.index));
|
||||||
|
}
|
||||||
|
return treffer;
|
||||||
|
}
|
||||||
|
|
||||||
const verdaechtig = [];
|
const verdaechtig = [];
|
||||||
for (const datei of dateien) {
|
for (const datei of dateien) {
|
||||||
/* Die eigene Datei bleibt aussen vor: Die Gegenprobe unten MUSS
|
/* Die eigene Datei bleibt aussen vor: Die Gegenproben unten
|
||||||
das gesuchte Muster als Text enthalten, sonst könnte sie nicht
|
MUESSEN das gesuchte Muster als Text enthalten, sonst koennten
|
||||||
beweisen, dass sie es erkennt. Sie würde sich sonst selbst
|
sie nicht beweisen, dass sie es erkennen. Sie wuerde sich sonst
|
||||||
anzeigen -- eine Warnung, die immer kommt, und die liest bald
|
selbst anzeigen -- eine Warnung, die immer kommt. */
|
||||||
niemand mehr. */
|
|
||||||
if (datei === "pruef-struktur.mjs") continue;
|
if (datei === "pruef-struktur.mjs") continue;
|
||||||
/* KOMMENTARE RAUS, ZEILEN BEHALTEN (16.09.2026).
|
/* KOMMENTARE RAUS, ZEILEN BEHALTEN (16.09.2026).
|
||||||
|
|
||||||
Hier stand `replace(…, " ")` -- ein Blockkommentar ueber zwanzig
|
Hier stand `replace(…, " ")` -- ein Blockkommentar ueber zwanzig
|
||||||
Zeilen wurde also zu einem Leerzeichen, und ab da zaehlte
|
Zeilen wurde also zu einem Leerzeichen, und ab da zaehlte
|
||||||
`split("\n").length` falsch. Gemeldet wurden Zeilennummern, die
|
`split("\n").length` falsch. Gemeldet wurden Zeilennummern, die
|
||||||
auf voellig anderen Code zeigten: pruef-eskalation.mjs:43 ist
|
auf voellig anderen Code zeigten. Jetzt bleibt je Zeile eine
|
||||||
eine Zeile ueber Kekse.
|
Zeile stehen. */
|
||||||
|
|
||||||
Wer einer solchen Meldung nachgeht, findet dort nichts, haelt
|
|
||||||
die Pruefung fuer kaputt und sieht beim naechsten Mal gar nicht
|
|
||||||
mehr nach. Jetzt bleibt je Zeile eine Zeile stehen. */
|
|
||||||
const text = readFileSync(join(SERVER, datei), "utf8")
|
const text = readFileSync(join(SERVER, datei), "utf8")
|
||||||
.replace(/\/\*[\s\S]*?\*\//g, (m) => m.replace(/[^\n]/g, " "));
|
.replace(/\/\*[\s\S]*?\*\//g, (m) => m.replace(/[^\n]/g, " "))
|
||||||
/* Das Muster ist eng gefasst: NUR toISOString() gefolgt von einem
|
.replace(/^\s*\/\/.*$/gm, "");
|
||||||
Schnitt auf zehn Zeichen -- also genau die Bildung eines
|
for (const z of utcTage(text)) verdaechtig.push(`${datei}:${z}`);
|
||||||
Tagesdatums. `new Date().toISOString()` allein (ein voller
|
|
||||||
Zeitstempel) ist voellig in Ordnung und faellt nicht darunter. */
|
|
||||||
for (const treffer of text.matchAll(/toISOString\(\)\s*\.\s*slice\(\s*0\s*,\s*10\s*\)/g)) {
|
|
||||||
const zeile = text.slice(0, treffer.index).split("\n").length;
|
|
||||||
verdaechtig.push(`${datei}:${zeile}`);
|
|
||||||
}
|
|
||||||
/* Und die zweite Schreibweise: erst in eine Variable, dann geschnitten. */
|
|
||||||
for (const treffer of text.matchAll(/=\s*(\w+)\s*\.\s*slice\(\s*0\s*,\s*10\s*\)/g)) {
|
|
||||||
const name = treffer[1];
|
|
||||||
/* Nur melden, wenn diese Variable aus toISOString() stammt. */
|
|
||||||
if (new RegExp(`(const|let)\\s+${name}\\s*=\\s*new Date\\(\\)\\.toISOString\\(\\)`).test(text)) {
|
|
||||||
const zeile = text.slice(0, treffer.index).split("\n").length;
|
|
||||||
verdaechtig.push(`${datei}:${zeile} (über ${name})`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ok(verdaechtig.length === 0,
|
ok(verdaechtig.length === 0,
|
||||||
verdaechtig.length
|
verdaechtig.length
|
||||||
? `bilden ihr Tagesdatum aus UTC statt Ortszeit — nachts zwischen `
|
? `bilden ihr Tagesdatum aus UTC statt Ortszeit — nachts zwischen `
|
||||||
+ `00:00 und 02:00 schlagen sie fälschlich an:\n `
|
+ `00:00 und 02:00 liegt es einen Tag zurueck:\n `
|
||||||
+ verdaechtig.join("\n ")
|
+ verdaechtig.join("\n ")
|
||||||
: `keine Prüfung bildet ihr Tagesdatum aus UTC (alle nutzen helfer-zeit.mjs)`);
|
: `keine der ${dateien.length} Dateien bildet einen Kalendertag aus UTC`);
|
||||||
|
|
||||||
/* GEGENPROBE: Findet das Muster überhaupt etwas? Ohne diesen
|
/* ---- GEGENPROBEN -------------------------------------------------
|
||||||
Nachweis wäre "0 Treffer" auch dann grün, wenn der reguläre
|
Eine Erkennung, die nichts findet, sieht genauso aus wie eine, die
|
||||||
Ausdruck gar nichts erkennt. */
|
nichts finden KANN. Heute Nacht war sie genau das: Die Schreibweise
|
||||||
const probe = "const jetzt = new Date().toISOString();\nconst heute = jetzt.slice(0, 10);";
|
mit einer Funktion kannte sie nicht, und die Anwendung sah sie gar
|
||||||
const erkanntA = /toISOString\(\)\s*\.\s*slice\(\s*0\s*,\s*10\s*\)/
|
nicht an. Beides steht jetzt hier als Probe. */
|
||||||
.test("new Date().toISOString().slice(0, 10)");
|
const probe = (code) => utcTage(code).length;
|
||||||
const erkanntB = /=\s*(\w+)\s*\.\s*slice\(\s*0\s*,\s*10\s*\)/.test(probe)
|
ok(probe('const h = new Date().toISOString().slice(0, 10);') === 1,
|
||||||
&& /(const|let)\s+jetzt\s*=\s*new Date\(\)\.toISOString\(\)/.test(probe);
|
"Gegenprobe: die direkte Schreibweise faellt auf");
|
||||||
ok(erkanntA && erkanntB,
|
ok(probe('const jetzt = () => new Date().toISOString();\nconst h = jetzt().slice(0, 10);') === 1,
|
||||||
"Gegenprobe: beide Schreibweisen werden erkannt (direkt und über eine Variable)");
|
" die ueber eine FUNKTION ebenfalls — genau die, die heute Nacht durchrutschte");
|
||||||
|
ok(probe('const jetzt = new Date().toISOString();\nconst h = jetzt.slice(0, 10);') === 1,
|
||||||
|
" und die ueber eine Variable");
|
||||||
|
ok(probe('const jetzt = () => new Date().toISOString();\n'
|
||||||
|
+ 'const iso = jetzt();\nconst h = iso.slice(0, 10);') === 1,
|
||||||
|
" auch ueber zwei Schritte");
|
||||||
|
ok(probe('const g = new Date(Date.now() - 30 * 86400000).toISOString().slice(0, 10);') === 1,
|
||||||
|
" und eine Rechnung auf Date.now()");
|
||||||
|
|
||||||
/* Und ein harmloser Zeitstempel darf NICHT anschlagen -- sonst wäre
|
ok(probe('const jetzt = new Date().toISOString();') === 0,
|
||||||
die Prüfung eine Warnung, die immer kommt. */
|
"Gegenprobe: ein voller Zeitstempel ohne Schnitt schlaegt NICHT an");
|
||||||
const harmlos = /toISOString\(\)\s*\.\s*slice\(\s*0\s*,\s*10\s*\)/
|
ok(probe('const b = new Date(Date.parse(tag + "T12:00:00Z") + n * 86400000)'
|
||||||
.test("const jetzt = new Date().toISOString();");
|
+ '.toISOString().slice(0, 10);') === 0,
|
||||||
ok(!harmlos, "Gegenprobe: ein voller Zeitstempel (ohne Schnitt) schlägt nicht an");
|
" und die Rechnung auf UTC-Mittag ebenfalls nicht — die ist richtig so");
|
||||||
|
ok(probe('const alsText = (d) => d.toISOString().slice(0, 10);') === 0,
|
||||||
|
" und ein Date, das von aussen kommt, auch nicht");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* =======================================================================
|
/* =======================================================================
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ const express = (await import("express")).default;
|
|||||||
const ec = express.response.cookie;
|
const ec = express.response.cookie;
|
||||||
express.response.cookie = function (n, w, o) { return ec.call(this, n, w, { ...(o || {}), secure: false }); };
|
express.response.cookie = function (n, w, o) { return ec.call(this, n, w, { ...(o || {}), secure: false }); };
|
||||||
import { notbremse } from "./helfer-notbremse.mjs";
|
import { notbremse } from "./helfer-notbremse.mjs";
|
||||||
|
import { heuteLokal } from "./helfer-tag.mjs";
|
||||||
await import("./index.js");
|
await import("./index.js");
|
||||||
notbremse(180_000, "pruef-treff-start");
|
notbremse(180_000, "pruef-treff-start");
|
||||||
await new Promise((r) => setTimeout(r, 700));
|
await new Promise((r) => setTimeout(r, 700));
|
||||||
@@ -301,7 +302,7 @@ melde("=== 3. Fuenfzehn Regeln auf einmal ===");
|
|||||||
const r = await fetch(`${BASIS}/workspace/api/bereich/treff`, {
|
const r = await fetch(`${BASIS}/workspace/api/bereich/treff`, {
|
||||||
method: "POST", headers: kopf(dogi),
|
method: "POST", headers: kopf(dogi),
|
||||||
body: JSON.stringify({ art: "frage", titel: `Frage Nummer ${i}`,
|
body: JSON.stringify({ art: "frage", titel: `Frage Nummer ${i}`,
|
||||||
datum: jetzt.slice(0, 10) }),
|
datum: heuteLokal() }),
|
||||||
});
|
});
|
||||||
letzte = r.status;
|
letzte = r.status;
|
||||||
if (r.status === 429) break;
|
if (r.status === 429) break;
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ const express = (await import("express")).default;
|
|||||||
const ec = express.response.cookie;
|
const ec = express.response.cookie;
|
||||||
express.response.cookie = function (n, w, o) { return ec.call(this, n, w, { ...(o || {}), secure: false }); };
|
express.response.cookie = function (n, w, o) { return ec.call(this, n, w, { ...(o || {}), secure: false }); };
|
||||||
import { notbremse } from "./helfer-notbremse.mjs";
|
import { notbremse } from "./helfer-notbremse.mjs";
|
||||||
|
import { heuteLokal } from "./helfer-tag.mjs";
|
||||||
await import("./index.js");
|
await import("./index.js");
|
||||||
notbremse(240_000, "pruef-treff");
|
notbremse(240_000, "pruef-treff");
|
||||||
await new Promise((r) => setTimeout(r, 700));
|
await new Promise((r) => setTimeout(r, 700));
|
||||||
@@ -126,9 +127,9 @@ const BRETTER = ["anschlag", "ansteht", "treff", "wunsch", "highlight", "regeln"
|
|||||||
vergessen. */
|
vergessen. */
|
||||||
const PERSOENLICH = ["Vertraulich melden", "Mein Steckbrief", "Support"];
|
const PERSOENLICH = ["Vertraulich melden", "Mein Steckbrief", "Support"];
|
||||||
for (const b of BRETTER) rein.run(b, Object.keys((await import("./workspace-bereiche.js")).BEREICHE[b].arten)[0],
|
for (const b of BRETTER) rein.run(b, Object.keys((await import("./workspace-bereiche.js")).BEREICHE[b].arten)[0],
|
||||||
`CREW-PROBE-${b.toUpperCase()}`, "", jetzt.slice(0, 10), jetzt, idDogi);
|
`CREW-PROBE-${b.toUpperCase()}`, "", heuteLokal(), jetzt, idDogi);
|
||||||
/* Und einer im Haus, den die Community NICHT sehen darf. */
|
/* Und einer im Haus, den die Community NICHT sehen darf. */
|
||||||
rein.run("ideen", "content", "HAUS-GEHEIM-4711", "", jetzt.slice(0, 10), jetzt, idDogi);
|
rein.run("ideen", "content", "HAUS-GEHEIM-4711", "", heuteLokal(), jetzt, idDogi);
|
||||||
d.close();
|
d.close();
|
||||||
|
|
||||||
/* Die Methode ist ein eigenes Argument, seit es Wege gibt, die PUT
|
/* Die Methode ist ein eigenes Argument, seit es Wege gibt, die PUT
|
||||||
@@ -851,7 +852,7 @@ melde("=== 6. Schreiben ===");
|
|||||||
Seiten der Grenze gemessen, sonst beweist es nichts: Eine
|
Seiten der Grenze gemessen, sonst beweist es nichts: Eine
|
||||||
Schreibsperre, die immer sperrt, ist keine Stufe. */
|
Schreibsperre, die immer sperrt, ist keine Stufe. */
|
||||||
const neu = await roh("/workspace/api/bereich/treff", CREW, { cookie: gast.keks },
|
const neu = await roh("/workspace/api/bereich/treff", CREW, { cookie: gast.keks },
|
||||||
{ art: "hallo", titel: "GAST-ZU-FRUEH-0001", text: "Hallo zusammen.", datum: jetzt.slice(0, 10) });
|
{ art: "hallo", titel: "GAST-ZU-FRUEH-0001", text: "Hallo zusammen.", datum: heuteLokal() });
|
||||||
ok(neu.code === 403, `wer neu ist, schreibt noch nicht (${neu.code})`);
|
ok(neu.code === 403, `wer neu ist, schreibt noch nicht (${neu.code})`);
|
||||||
|
|
||||||
const lage0 = JSON.parse((await roh("/workspace/api/treff/lage", CREW, { cookie: gast.keks })).text);
|
const lage0 = JSON.parse((await roh("/workspace/api/treff/lage", CREW, { cookie: gast.keks })).text);
|
||||||
@@ -867,7 +868,7 @@ melde("=== 6. Schreiben ===");
|
|||||||
dd.close();
|
dd.close();
|
||||||
|
|
||||||
const a = await roh("/workspace/api/bereich/treff", CREW, { cookie: gast.keks },
|
const a = await roh("/workspace/api/bereich/treff", CREW, { cookie: gast.keks },
|
||||||
{ art: "hallo", titel: "GAST-SCHREIBT-8899", text: "Hallo zusammen.", datum: jetzt.slice(0, 10) });
|
{ art: "hallo", titel: "GAST-SCHREIBT-8899", text: "Hallo zusammen.", datum: heuteLokal() });
|
||||||
ok(a.code === 200 || a.code === 201, `nach acht Tagen schon (${a.code})`);
|
ok(a.code === 200 || a.code === 201, `nach acht Tagen schon (${a.code})`);
|
||||||
|
|
||||||
/* UND SECHS TAGE REICHEN NICHT. Die andere Seite derselben Grenze --
|
/* UND SECHS TAGE REICHEN NICHT. Die andere Seite derselben Grenze --
|
||||||
@@ -878,7 +879,7 @@ melde("=== 6. Schreiben ===");
|
|||||||
.run(new Date(Date.now() - 6 * 86400000).toISOString(), idGast);
|
.run(new Date(Date.now() - 6 * 86400000).toISOString(), idGast);
|
||||||
dd2.close();
|
dd2.close();
|
||||||
const knapp = await roh("/workspace/api/bereich/treff", CREW, { cookie: gast.keks },
|
const knapp = await roh("/workspace/api/bereich/treff", CREW, { cookie: gast.keks },
|
||||||
{ art: "hallo", titel: "GAST-ZU-FRUEH-0002", text: "Und?", datum: jetzt.slice(0, 10) });
|
{ art: "hallo", titel: "GAST-ZU-FRUEH-0002", text: "Und?", datum: heuteLokal() });
|
||||||
ok(knapp.code === 403, `sechs Tage reichen nicht (${knapp.code})`);
|
ok(knapp.code === 403, `sechs Tage reichen nicht (${knapp.code})`);
|
||||||
const dd3 = new DatabaseSync(process.env.WORKSPACE_DB);
|
const dd3 = new DatabaseSync(process.env.WORKSPACE_DB);
|
||||||
dd3.prepare("UPDATE personen SET erstellt = ? WHERE id = ?")
|
dd3.prepare("UPDATE personen SET erstellt = ? WHERE id = ?")
|
||||||
@@ -888,7 +889,7 @@ melde("=== 6. Schreiben ===");
|
|||||||
/* Und auf ein Brett des Teams kommt er auch als "Dabei" nicht. */
|
/* Und auf ein Brett des Teams kommt er auch als "Dabei" nicht. */
|
||||||
const brettDesTeams = await roh("/workspace/api/bereich/anschlag", CREW, { cookie: gast.keks },
|
const brettDesTeams = await roh("/workspace/api/bereich/anschlag", CREW, { cookie: gast.keks },
|
||||||
{ art: Object.keys(BEREICHE.anschlag.arten)[0], titel: "GAST-AM-ANSCHLAG-0001",
|
{ art: Object.keys(BEREICHE.anschlag.arten)[0], titel: "GAST-AM-ANSCHLAG-0001",
|
||||||
text: "Ansage", datum: jetzt.slice(0, 10) });
|
text: "Ansage", datum: heuteLokal() });
|
||||||
ok(brettDesTeams.code === 403, `aufs Anschlagbrett schreibt nur das Team (${brettDesTeams.code})`);
|
ok(brettDesTeams.code === 403, `aufs Anschlagbrett schreibt nur das Team (${brettDesTeams.code})`);
|
||||||
|
|
||||||
const beiDogi = await brett("treff", HAUS, kDogi);
|
const beiDogi = await brett("treff", HAUS, kDogi);
|
||||||
@@ -901,7 +902,7 @@ melde("=== 6. Schreiben ===");
|
|||||||
{
|
{
|
||||||
/* UND NICHT IN EIN BRETT DES HAUSES. */
|
/* UND NICHT IN EIN BRETT DES HAUSES. */
|
||||||
const a = await roh("/workspace/api/bereich/ideen", CREW, { cookie: gast.keks },
|
const a = await roh("/workspace/api/bereich/ideen", CREW, { cookie: gast.keks },
|
||||||
{ art: "content", titel: "GAST-IM-HAUS-0000", text: "", datum: jetzt.slice(0, 10) });
|
{ art: "content", titel: "GAST-IM-HAUS-0000", text: "", datum: heuteLokal() });
|
||||||
ok(a.code !== 200 && a.code !== 201, `aber nicht in ein Brett des Hauses (${a.code})`);
|
ok(a.code !== 200 && a.code !== 201, `aber nicht in ein Brett des Hauses (${a.code})`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ const express = (await import("express")).default;
|
|||||||
const ec = express.response.cookie;
|
const ec = express.response.cookie;
|
||||||
express.response.cookie = function (n, w, o) { return ec.call(this, n, w, { ...(o || {}), secure: false }); };
|
express.response.cookie = function (n, w, o) { return ec.call(this, n, w, { ...(o || {}), secure: false }); };
|
||||||
import { notbremse } from "./helfer-notbremse.mjs";
|
import { notbremse } from "./helfer-notbremse.mjs";
|
||||||
|
import { heuteLokal } from "./helfer-tag.mjs";
|
||||||
await import("./index.js");
|
await import("./index.js");
|
||||||
notbremse(240_000, "pruef-uebergang");
|
notbremse(240_000, "pruef-uebergang");
|
||||||
await new Promise((r) => setTimeout(r, 700));
|
await new Promise((r) => setTimeout(r, 700));
|
||||||
@@ -100,7 +101,7 @@ let idDogi, idHand, idFrida, idMara, idNina, idTalent, idZweit;
|
|||||||
const neuTalent = (titel) => {
|
const neuTalent = (titel) => {
|
||||||
d.prepare("INSERT INTO eintraege (bereich, art, titel, text, datum, erstellt, erstellt_von, einsatz)"
|
d.prepare("INSERT INTO eintraege (bereich, art, titel, text, datum, erstellt, erstellt_von, einsatz)"
|
||||||
+ " VALUES ('talente','ruhig',?,?,?,?,?,?)")
|
+ " VALUES ('talente','ruhig',?,?,?,?,?,?)")
|
||||||
.run(titel, "Faellt seit Wochen auf.", jetzt.slice(0, 10), jetzt, idDogi, "Dienstag im Stream");
|
.run(titel, "Faellt seit Wochen auf.", heuteLokal(), jetzt, idDogi, "Dienstag im Stream");
|
||||||
return d.prepare("SELECT last_insert_rowid() AS id").get().id;
|
return d.prepare("SELECT last_insert_rowid() AS id").get().id;
|
||||||
};
|
};
|
||||||
idTalent = neuTalent("Kessi aus dem Chat");
|
idTalent = neuTalent("Kessi aus dem Chat");
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ const express = (await import("express")).default;
|
|||||||
const ec = express.response.cookie;
|
const ec = express.response.cookie;
|
||||||
express.response.cookie = function (n, w, o) { return ec.call(this, n, w, { ...(o || {}), secure: false }); };
|
express.response.cookie = function (n, w, o) { return ec.call(this, n, w, { ...(o || {}), secure: false }); };
|
||||||
import { notbremse } from "./helfer-notbremse.mjs";
|
import { notbremse } from "./helfer-notbremse.mjs";
|
||||||
|
import { heuteLokal } from "./helfer-tag.mjs";
|
||||||
await import("./index.js");
|
await import("./index.js");
|
||||||
notbremse(180_000, "pruef-uebernahme");
|
notbremse(180_000, "pruef-uebernahme");
|
||||||
await new Promise((r) => setTimeout(r, 700));
|
await new Promise((r) => setTimeout(r, 700));
|
||||||
@@ -92,14 +93,14 @@ let idDogi, idLuna, idIdee, idTreff, idIdeeHoch;
|
|||||||
(bereich, art, titel, text, datum, dringlichkeit, status, creator_id, erstellt, erstellt_von)
|
(bereich, art, titel, text, datum, dringlichkeit, status, creator_id, erstellt, erstellt_von)
|
||||||
VALUES (?,?,?,?,?,?,'offen',?,?,?)`);
|
VALUES (?,?,?,?,?,?,'offen',?,?,?)`);
|
||||||
rein.run("ideen", "content", "Reihe über Technik", "Drei Teile, je fünf Minuten.",
|
rein.run("ideen", "content", "Reihe über Technik", "Drei Teile, je fünf Minuten.",
|
||||||
jetzt.slice(0, 10), "mittel", idLuna, jetzt, idDogi);
|
heuteLokal(), "mittel", idLuna, jetzt, idDogi);
|
||||||
idIdee = d.prepare("SELECT last_insert_rowid() AS id").get().id;
|
idIdee = d.prepare("SELECT last_insert_rowid() AS id").get().id;
|
||||||
rein.run("ideen", "content", "Dringende Idee", "Muss diese Woche.",
|
rein.run("ideen", "content", "Dringende Idee", "Muss diese Woche.",
|
||||||
jetzt.slice(0, 10), "hoch", null, jetzt, idDogi);
|
heuteLokal(), "hoch", null, jetzt, idDogi);
|
||||||
idIdeeHoch = d.prepare("SELECT last_insert_rowid() AS id").get().id;
|
idIdeeHoch = d.prepare("SELECT last_insert_rowid() AS id").get().id;
|
||||||
d.prepare(`INSERT INTO eintraege (bereich, art, titel, text, datum, erstellt, erstellt_von)
|
d.prepare(`INSERT INTO eintraege (bereich, art, titel, text, datum, erstellt, erstellt_von)
|
||||||
VALUES ('treff','hallo','Beitrag aus dem Rudel','Hallo zusammen',?,?,?)`)
|
VALUES ('treff','hallo','Beitrag aus dem Rudel','Hallo zusammen',?,?,?)`)
|
||||||
.run(jetzt.slice(0, 10), jetzt, idDogi);
|
.run(heuteLokal(), jetzt, idDogi);
|
||||||
idTreff = d.prepare("SELECT last_insert_rowid() AS id").get().id;
|
idTreff = d.prepare("SELECT last_insert_rowid() AS id").get().id;
|
||||||
d.close();
|
d.close();
|
||||||
}
|
}
|
||||||
@@ -314,7 +315,7 @@ melde("=== 8. Im Browser ===");
|
|||||||
d.prepare(`INSERT INTO eintraege
|
d.prepare(`INSERT INTO eintraege
|
||||||
(bereich, art, titel, text, datum, dringlichkeit, status, erstellt, erstellt_von)
|
(bereich, art, titel, text, datum, dringlichkeit, status, erstellt, erstellt_von)
|
||||||
VALUES ('ideen','content','BILDSCHIRM-IDEE','Zum Anklicken.',?,'mittel','offen',?,?)`)
|
VALUES ('ideen','content','BILDSCHIRM-IDEE','Zum Anklicken.',?,'mittel','offen',?,?)`)
|
||||||
.run(jetzt.slice(0, 10), jetzt, idDogi);
|
.run(heuteLokal(), jetzt, idDogi);
|
||||||
d.close();
|
d.close();
|
||||||
|
|
||||||
await seite.goto(`http://127.0.0.1:${PORT}/workspace/`, { waitUntil: "domcontentloaded" });
|
await seite.goto(`http://127.0.0.1:${PORT}/workspace/`, { waitUntil: "domcontentloaded" });
|
||||||
|
|||||||
@@ -125,6 +125,7 @@ const express = (await import("express")).default;
|
|||||||
const ec = express.response.cookie;
|
const ec = express.response.cookie;
|
||||||
express.response.cookie = function (n, w, o) { return ec.call(this, n, w, { ...(o || {}), secure: false }); };
|
express.response.cookie = function (n, w, o) { return ec.call(this, n, w, { ...(o || {}), secure: false }); };
|
||||||
import { notbremse } from "./helfer-notbremse.mjs";
|
import { notbremse } from "./helfer-notbremse.mjs";
|
||||||
|
import { heuteLokal } from "./helfer-tag.mjs";
|
||||||
await import("./index.js");
|
await import("./index.js");
|
||||||
notbremse(180_000, "pruef-video");
|
notbremse(180_000, "pruef-video");
|
||||||
await new Promise((r) => setTimeout(r, 700));
|
await new Promise((r) => setTimeout(r, 700));
|
||||||
@@ -503,7 +504,7 @@ melde("=== 5c. Aus einem Wunsch wird ein Video ===");
|
|||||||
const { lastInsertRowid } = db3.prepare(`
|
const { lastInsertRowid } = db3.prepare(`
|
||||||
INSERT INTO eintraege (bereich, art, titel, datum, status, erstellt, erstellt_von)
|
INSERT INTO eintraege (bereich, art, titel, datum, status, erstellt, erstellt_von)
|
||||||
VALUES (?,?,?,?, 'offen', ?, (SELECT id FROM personen LIMIT 1))`)
|
VALUES (?,?,?,?, 'offen', ?, (SELECT id FROM personen LIMIT 1))`)
|
||||||
.run(bereich, art, titel, nun.slice(0, 10), nun);
|
.run(bereich, art, titel, heuteLokal(), nun);
|
||||||
return Number(lastInsertRowid);
|
return Number(lastInsertRowid);
|
||||||
};
|
};
|
||||||
const wunschId = anlegen("wunsch", "wunsch", "Bitte mal Casper beim Baden zeigen");
|
const wunschId = anlegen("wunsch", "wunsch", "Bitte mal Casper beim Baden zeigen");
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ const express = (await import("express")).default;
|
|||||||
const ec = express.response.cookie;
|
const ec = express.response.cookie;
|
||||||
express.response.cookie = function (n, w, o) { return ec.call(this, n, w, { ...(o || {}), secure: false }); };
|
express.response.cookie = function (n, w, o) { return ec.call(this, n, w, { ...(o || {}), secure: false }); };
|
||||||
import { notbremse } from "./helfer-notbremse.mjs";
|
import { notbremse } from "./helfer-notbremse.mjs";
|
||||||
|
import { heuteLokal } from "./helfer-tag.mjs";
|
||||||
await import("./index.js");
|
await import("./index.js");
|
||||||
notbremse(150_000, "pruef-wege-nach-draussen");
|
notbremse(150_000, "pruef-wege-nach-draussen");
|
||||||
await new Promise((r) => setTimeout(r, 700));
|
await new Promise((r) => setTimeout(r, 700));
|
||||||
@@ -308,20 +309,20 @@ const VIDEO = "https://www.tiktok.com/@dogfather0804/video/7500000000000000000";
|
|||||||
d.prepare("INSERT INTO eintraege (bereich, art, titel, text, datum, status, erstellt, erstellt_von,"
|
d.prepare("INSERT INTO eintraege (bereich, art, titel, text, datum, status, erstellt, erstellt_von,"
|
||||||
+ " quelle_url, quelle_kanal) VALUES (?,?,?,?,?,?,?,?,?,?)")
|
+ " quelle_url, quelle_kanal) VALUES (?,?,?,?,?,?,?,?,?,?)")
|
||||||
.run("highlight", "clip", "Wer ist euer Komet", "Schreibt es in die Kommentare",
|
.run("highlight", "clip", "Wer ist euer Komet", "Schreibt es in die Kommentare",
|
||||||
jetzt.slice(0, 10), "offen", jetzt, wer, VIDEO, "tiktok");
|
heuteLokal(), "offen", jetzt, wer, VIDEO, "tiktok");
|
||||||
|
|
||||||
/* (b) ohne Video -- darf NICHT klickbar sein */
|
/* (b) ohne Video -- darf NICHT klickbar sein */
|
||||||
d.prepare("INSERT INTO eintraege (bereich, art, titel, text, datum, status, erstellt, erstellt_von)"
|
d.prepare("INSERT INTO eintraege (bereich, art, titel, text, datum, status, erstellt, erstellt_von)"
|
||||||
+ " VALUES (?,?,?,?,?,?,?,?)")
|
+ " VALUES (?,?,?,?,?,?,?,?)")
|
||||||
.run("highlight", "clip", "Nur ein Bild", "Ohne Quelle",
|
.run("highlight", "clip", "Nur ein Bild", "Ohne Quelle",
|
||||||
jetzt.slice(0, 10), "offen", jetzt, wer);
|
heuteLokal(), "offen", jetzt, wer);
|
||||||
|
|
||||||
/* (c) Video bei TikTok geloescht -- darf NICHT klickbar sein, sonst
|
/* (c) Video bei TikTok geloescht -- darf NICHT klickbar sein, sonst
|
||||||
fuehrt der Klick auf eine Fehlerseite und WIR sehen kaputt aus */
|
fuehrt der Klick auf eine Fehlerseite und WIR sehen kaputt aus */
|
||||||
d.prepare("INSERT INTO eintraege (bereich, art, titel, text, datum, status, erstellt, erstellt_von,"
|
d.prepare("INSERT INTO eintraege (bereich, art, titel, text, datum, status, erstellt, erstellt_von,"
|
||||||
+ " quelle_url, quelle_kanal, quelle_fehlt_seit) VALUES (?,?,?,?,?,?,?,?,?,?,?)")
|
+ " quelle_url, quelle_kanal, quelle_fehlt_seit) VALUES (?,?,?,?,?,?,?,?,?,?,?)")
|
||||||
.run("highlight", "clip", "Nicht mehr da", "Wurde geloescht",
|
.run("highlight", "clip", "Nicht mehr da", "Wurde geloescht",
|
||||||
jetzt.slice(0, 10), "offen", jetzt, wer, VIDEO, "tiktok", jetzt);
|
heuteLokal(), "offen", jetzt, wer, VIDEO, "tiktok", jetzt);
|
||||||
|
|
||||||
/* EIN ECHTES BILD AN DIE ERSTE KARTE.
|
/* EIN ECHTES BILD AN DIE ERSTE KARTE.
|
||||||
|
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ import { unterstuetzungAufraeumen } from "./workspace-unterstuetzung.js";
|
|||||||
import {
|
import {
|
||||||
db, sitzungLesen, istDogFather, protokolliere, echteIp,
|
db, sitzungLesen, istDogFather, protokolliere, echteIp,
|
||||||
einstellung, einstellungSetzen,
|
einstellung, einstellungSetzen,
|
||||||
|
tagLokal,
|
||||||
} from "./workspace.js";
|
} from "./workspace.js";
|
||||||
|
|
||||||
export const aufbewahrungRouter = express.Router();
|
export const aufbewahrungRouter = express.Router();
|
||||||
@@ -392,7 +393,11 @@ export const FRISTEN = [
|
|||||||
+ "gezählt wird je Weg und Tag, nicht je Mensch.",
|
+ "gezählt wird je Weg und Tag, nicht je Mensch.",
|
||||||
offen: (d) => zaehle(d,
|
offen: (d) => zaehle(d,
|
||||||
"SELECT COUNT(*) AS n FROM unterstuetzung_striche WHERE tag < ?",
|
"SELECT COUNT(*) AS n FROM unterstuetzung_striche WHERE tag < ?",
|
||||||
vorTagen(ZAEHLUNG_TAGE).slice(0, 10)),
|
/* Dieselbe Grenze wie in unterstuetzungAufraeumen -- und
|
||||||
|
dieselbe Rechnung, in Ortszeit (01.10.2026). Stuenden hier
|
||||||
|
zwei verschiedene, zeigte die Vorschau eine andere Zahl an,
|
||||||
|
als das Raeumen danach loescht. */
|
||||||
|
tagLokal(-ZAEHLUNG_TAGE)),
|
||||||
raeumen: () => unterstuetzungAufraeumen(),
|
raeumen: () => unterstuetzungAufraeumen(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -547,7 +547,10 @@ aufgabenRouter.get("/workspace/api/uebersicht", (req, res) => {
|
|||||||
.prepare(`SELECT COUNT(*) AS n ${VERBUND} WHERE ${wo}${zusatz}`)
|
.prepare(`SELECT COUNT(*) AS n ${VERBUND} WHERE ${wo}${zusatz}`)
|
||||||
.get(...werte, ...extra).n;
|
.get(...werte, ...extra).n;
|
||||||
|
|
||||||
const heute = jetzt().slice(0, 10);
|
/* ORTSZEIT (01.10.2026): `jetzt().slice(0, 10)` waere der UTC-Tag.
|
||||||
|
Nachts zwischen 00:00 und 02:00 haette eine Aufgabe mit Frist
|
||||||
|
„gestern" noch als nicht ueberfaellig gegolten. */
|
||||||
|
const heute = heuteLokal();
|
||||||
|
|
||||||
/* ABGEBROCHENE SIND NICHT "NOCH ZU TUN" (08.09.2026).
|
/* ABGEBROCHENE SIND NICHT "NOCH ZU TUN" (08.09.2026).
|
||||||
|
|
||||||
|
|||||||
@@ -1775,7 +1775,13 @@ function pruefe(bereich, körper, { neu }) {
|
|||||||
}
|
}
|
||||||
if (neu || körper.datum !== undefined) {
|
if (neu || körper.datum !== undefined) {
|
||||||
const d = String(körper.datum ?? "").trim();
|
const d = String(körper.datum ?? "").trim();
|
||||||
if (!d) aus.datum = jetzt().slice(0, 10);
|
/* ORTSZEIT, NICHT UTC (01.10.2026). Hier stand
|
||||||
|
`jetzt().slice(0, 10)` -- der UTC-Tag. Zwischen 00:00 und 02:00
|
||||||
|
Ortszeit ist das der VORTAG: Ein Eintrag ohne Datum, nachts
|
||||||
|
angelegt, trug gestern. Bei „Was ansteht" landet er damit im
|
||||||
|
Abschnitt „Vorbei", und der ist von sich aus zugeklappt -- der
|
||||||
|
Eintrag ist also da und trotzdem nicht zu sehen. */
|
||||||
|
if (!d) aus.datum = heuteLokal();
|
||||||
else if (!/^\d{4}-\d{2}-\d{2}$/.test(d) || Number.isNaN(Date.parse(d))) {
|
else if (!/^\d{4}-\d{2}-\d{2}$/.test(d) || Number.isNaN(Date.parse(d))) {
|
||||||
fehler.push("Datum ist ungültig.");
|
fehler.push("Datum ist ungültig.");
|
||||||
} else aus.datum = d;
|
} else aus.datum = d;
|
||||||
@@ -2130,7 +2136,10 @@ bereicheRouter.post("/workspace/api/bereich/:bereich/start", gleicheHerkunft, (r
|
|||||||
erstellt_von, haus)
|
erstellt_von, haus)
|
||||||
VALUES (?,?,?,?,?, 'offen', ?, ?, ?)`)
|
VALUES (?,?,?,?,?, 'offen', ?, ?, ?)`)
|
||||||
.run(bereich, v.art, v.titel, v.text ?? null,
|
.run(bereich, v.art, v.titel, v.text ?? null,
|
||||||
jetzt().slice(0, 10), jetzt(), req.person.id, req.person.haus || null);
|
/* Der TAG in Ortszeit, der ZEITSTEMPEL in UTC -- das ist kein
|
||||||
|
Widerspruch: Ein Zeitpunkt ist ueberall derselbe, ein
|
||||||
|
Kalendertag nicht. */
|
||||||
|
heuteLokal(), jetzt(), req.person.id, req.person.haus || null);
|
||||||
|
|
||||||
/* UND SOFORT FREIGEBEN (17.09.2026) -- der Fehler, den Filipe
|
/* UND SOFORT FREIGEBEN (17.09.2026) -- der Fehler, den Filipe
|
||||||
auf seinem Bildschirm gesehen hat.
|
auf seinem Bildschirm gesehen hat.
|
||||||
@@ -2243,7 +2252,14 @@ bereicheRouter.post("/workspace/api/bereich/:bereich/:id/daraus",
|
|||||||
VALUES (?,?,?,?,?, 'offen', ?,?,?,?)`)
|
VALUES (?,?,?,?,?, 'offen', ?,?,?,?)`)
|
||||||
.run(nach, art, quelle.titel,
|
.run(nach, art, quelle.titel,
|
||||||
String(req.body?.text ?? "").trim().slice(0, TEXT_MAX) || null,
|
String(req.body?.text ?? "").trim().slice(0, TEXT_MAX) || null,
|
||||||
jetzt().slice(0, 10), jetzt(), req.person.id, quelle.id,
|
/* DIE STELLE, AN DER ES AUFGEFALLEN IST (01.10.2026).
|
||||||
|
pruef-kreislauf legt einen Wunsch mit dem heutigen Datum an
|
||||||
|
und macht daraus einen Termin; gemessen um 01:22 kam
|
||||||
|
`2026-09-30` heraus statt `2026-10-01`. Der Termin lag
|
||||||
|
damit in der Vergangenheit, stand auf dem Brett unter
|
||||||
|
„Vorbei" und war zugeklappt -- waehrend beim Wunsch
|
||||||
|
„Daraus wurde ein Termin" zu lesen war. */
|
||||||
|
heuteLokal(), jetzt(), req.person.id, quelle.id,
|
||||||
req.person.haus || null);
|
req.person.haus || null);
|
||||||
|
|
||||||
protokolliere("bereich_daraus", {
|
protokolliere("bereich_daraus", {
|
||||||
|
|||||||
@@ -548,7 +548,8 @@ bewerbungRouter.put("/workspace/api/bewerbung/:id/weg", express.json({ limit: "8
|
|||||||
.run(b.nenn_name,
|
.run(b.nenn_name,
|
||||||
`Hat sich selbst gemeldet (Anfrage #${id}).`
|
`Hat sich selbst gemeldet (Anfrage #${id}).`
|
||||||
+ (antworten.get("warum") ? `\n\nWarum: ${antworten.get("warum")}` : ""),
|
+ (antworten.get("warum") ? `\n\nWarum: ${antworten.get("warum")}` : ""),
|
||||||
t.slice(0, 10), t, req.person.id, einsatz);
|
/* Der TAG in Ortszeit (01.10.2026), der Zeitstempel in UTC. */
|
||||||
|
heuteLokal(), t, req.person.id, einsatz);
|
||||||
eintragId = Number(lastInsertRowid);
|
eintragId = Number(lastInsertRowid);
|
||||||
|
|
||||||
/* AUF „ANGESPROCHEN" und nicht auf „aufgefallen": Die ersten
|
/* AUF „ANGESPROCHEN" und nicht auf „aufgefallen": Die ersten
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import express from "express";
|
|||||||
import {
|
import {
|
||||||
db, protokolliere, echteIp, sitzungLesen, betreutWo, darfCreator, betreuteIds,
|
db, protokolliere, echteIp, sitzungLesen, betreutWo, darfCreator, betreuteIds,
|
||||||
istLeitung, istDogFather, siehtAlles, tagLokal,
|
istLeitung, istDogFather, siehtAlles, tagLokal,
|
||||||
|
heuteLokal,
|
||||||
} from "./workspace.js";
|
} from "./workspace.js";
|
||||||
|
|
||||||
export const contentRouter = express.Router();
|
export const contentRouter = express.Router();
|
||||||
@@ -39,7 +40,10 @@ const NAME_MAX = 40;
|
|||||||
const SAEULEN_MAX = 5;
|
const SAEULEN_MAX = 5;
|
||||||
|
|
||||||
const jetzt = () => new Date().toISOString();
|
const jetzt = () => new Date().toISOString();
|
||||||
const heute = () => jetzt().slice(0, 10);
|
/* ORTSZEIT (01.10.2026). Stand hier als `jetzt().slice(0, 10)` --
|
||||||
|
der UTC-Tag, also nachts der Vortag. Dieses `heute()` schreibt das
|
||||||
|
Datum neuer Eintraege, der Fehler waere dauerhaft in den Daten. */
|
||||||
|
const heute = () => heuteLokal();
|
||||||
|
|
||||||
function angemeldet(req, res, next) {
|
function angemeldet(req, res, next) {
|
||||||
const person = sitzungLesen(req);
|
const person = sitzungLesen(req);
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ import express from "express";
|
|||||||
import {
|
import {
|
||||||
db, sitzungLesen, protokolliere, echteIp, fuehrtTeamDogi, ROLLEN_NAME,
|
db, sitzungLesen, protokolliere, echteIp, fuehrtTeamDogi, ROLLEN_NAME,
|
||||||
ROLLEN_SORTIERUNG, MODI_KATEGORIEN, kategorienFuer, darfKatalogBekommen,
|
ROLLEN_SORTIERUNG, MODI_KATEGORIEN, kategorienFuer, darfKatalogBekommen,
|
||||||
|
tagLokal,
|
||||||
} from "./workspace.js";
|
} from "./workspace.js";
|
||||||
/* Die Aufgaben, die ein Neuer bekommen kann -- dieselbe Liste, aus der
|
/* Die Aufgaben, die ein Neuer bekommen kann -- dieselbe Liste, aus der
|
||||||
auch die Aufgabenseite ihre Vorschlaege baut. Eine zweite waere die,
|
auch die Aufgabenseite ihre Vorschlaege baut. Eine zweite waere die,
|
||||||
@@ -1145,7 +1146,12 @@ entwicklungRouter.post("/workspace/api/entwicklung/person/:id/:schluessel/schrit
|
|||||||
AND status NOT IN ('erledigt','abgebrochen')`).get(id, schluessel);
|
AND status NOT IN ('erledigt','abgebrochen')`).get(id, schluessel);
|
||||||
if (offen) return res.status(400).json({ fehler: "schon_da", aufgabe_id: offen.id });
|
if (offen) return res.status(400).json({ fehler: "schon_da", aufgabe_id: offen.id });
|
||||||
|
|
||||||
const frist = new Date(Date.now() + SCHRITT_TAGE * 86400000).toISOString().slice(0, 10);
|
/* ORTSZEIT (01.10.2026). Mit dem UTC-Tag lag die Frist nachts
|
||||||
|
zwischen 00:00 und 02:00 einen Tag zu frueh -- derselbe
|
||||||
|
Fehler, der am 30.09. schon einmal bei „morgen" gefunden
|
||||||
|
wurde. Eine Frist, die einen Tag zu frueh steht, macht eine
|
||||||
|
Aufgabe ueberfaellig, die es nicht ist. */
|
||||||
|
const frist = tagLokal(SCHRITT_TAGE);
|
||||||
const jetztIso = jetzt();
|
const jetztIso = jetzt();
|
||||||
db().prepare(`INSERT INTO aufgaben
|
db().prepare(`INSERT INTO aufgaben
|
||||||
(titel, beschreibung, status, prioritaet, verantwortlich_id,
|
(titel, beschreibung, status, prioritaet, verantwortlich_id,
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ import express from "express";
|
|||||||
import { randomBytes, timingSafeEqual } from "node:crypto";
|
import { randomBytes, timingSafeEqual } from "node:crypto";
|
||||||
import {
|
import {
|
||||||
db, protokolliere, echteIp, sitzungLesen, termineSichtbar, externSql,
|
db, protokolliere, echteIp, sitzungLesen, termineSichtbar, externSql,
|
||||||
|
tagLokal,
|
||||||
} from "./workspace.js";
|
} from "./workspace.js";
|
||||||
|
|
||||||
export const icsRouter = express.Router();
|
export const icsRouter = express.Router();
|
||||||
@@ -335,9 +336,13 @@ icsRouter.get("/workspace/kalender/:datei", (req, res) => {
|
|||||||
/* Ein Jahr rueckwaerts, ein Jahr vorwaerts. Alles auszuliefern
|
/* Ein Jahr rueckwaerts, ein Jahr vorwaerts. Alles auszuliefern
|
||||||
waere bei jedem Abruf die ganze Geschichte; ein Kalender braucht
|
waere bei jedem Abruf die ganze Geschichte; ein Kalender braucht
|
||||||
sie nicht, und die Datei waechst sonst ohne Ende. */
|
sie nicht, und die Datei waechst sonst ohne Ende. */
|
||||||
const heute = new Date();
|
/* ORTSZEIT (01.10.2026). Der Schaden waere hier klein -- ein
|
||||||
const vor = new Date(heute.getTime() - 365 * 86400000).toISOString().slice(0, 10);
|
Fenster von zwei Jahren verschiebt sich um einen Tag --, aber
|
||||||
const nach = new Date(heute.getTime() + 365 * 86400000).toISOString().slice(0, 10);
|
eine Ausnahme von der Regel ist teurer als die Aenderung: Wer
|
||||||
|
spaeter eine Liste der erlaubten Ausnahmen pflegen muss, pflegt
|
||||||
|
sie nicht. */
|
||||||
|
const vor = tagLokal(-365);
|
||||||
|
const nach = tagLokal(365);
|
||||||
|
|
||||||
const termine = db().prepare(`
|
const termine = db().prepare(`
|
||||||
SELECT ${SPALTEN} ${VERBUND}
|
SELECT ${SPALTEN} ${VERBUND}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
import express from "express";
|
import express from "express";
|
||||||
import {
|
import {
|
||||||
db, protokolliere, echteIp, sitzungLesen, betreuteIds, darfCreator, istLeitung, istDogFather, siehtAlles, sichtbareCreatorIds,
|
db, protokolliere, echteIp, sitzungLesen, betreuteIds, darfCreator, istLeitung, istDogFather, siehtAlles, sichtbareCreatorIds,
|
||||||
|
heuteLokal, tagLokal,
|
||||||
} from "./workspace.js";
|
} from "./workspace.js";
|
||||||
import { verteilen } from "./workspace-womit.js";
|
import { verteilen } from "./workspace-womit.js";
|
||||||
import { BEREICHE } from "./workspace-bereiche.js";
|
import { BEREICHE } from "./workspace-bereiche.js";
|
||||||
@@ -29,6 +30,10 @@ export const reportRouter = express.Router();
|
|||||||
|
|
||||||
const jetzt = () => new Date().toISOString();
|
const jetzt = () => new Date().toISOString();
|
||||||
const tagOffset = (tage) => new Date(Date.now() - tage * 86400_000).toISOString();
|
const tagOffset = (tage) => new Date(Date.now() - tage * 86400_000).toISOString();
|
||||||
|
/* Derselbe Versatz als TAG -- in Ortszeit (01.10.2026). `tagOffset`
|
||||||
|
bleibt, wo ein voller Zeitstempel gebraucht wird; wo ein
|
||||||
|
Kalendertag gemeint ist, zaehlt die Ortszeit. */
|
||||||
|
const tagOffsetTag = (tage) => tagLokal(-tage);
|
||||||
|
|
||||||
function angemeldet(req, res, next) {
|
function angemeldet(req, res, next) {
|
||||||
const person = sitzungLesen(req);
|
const person = sitzungLesen(req);
|
||||||
@@ -101,11 +106,13 @@ reportRouter.get("/workspace/api/report", (req, res) => {
|
|||||||
const creator = zielCreator(req);
|
const creator = zielCreator(req);
|
||||||
|
|
||||||
const jetztIso = jetzt();
|
const jetztIso = jetzt();
|
||||||
const heute = jetztIso.slice(0, 10);
|
/* ORTSZEIT (01.10.2026), nicht der UTC-Tag -- sonst faengt der
|
||||||
|
Zeitraum eines Berichts nachts einen Tag zu frueh an. */
|
||||||
|
const heute = heuteLokal();
|
||||||
const abIso = tagOffset(tage);
|
const abIso = tagOffset(tage);
|
||||||
const davorIso = tagOffset(tage * 2);
|
const davorIso = tagOffset(tage * 2);
|
||||||
const ab = abIso.slice(0, 10);
|
const ab = tagOffsetTag(tage);
|
||||||
const davor = davorIso.slice(0, 10);
|
const davor = tagOffsetTag(tage * 2);
|
||||||
|
|
||||||
/* Einschraenkung auf einen Creator, je Tabelle einmal formuliert. */
|
/* Einschraenkung auf einen Creator, je Tabelle einmal formuliert. */
|
||||||
const nurA = creator ? " AND (a.creator_id = ? OR a.verantwortlich_id = ?)" : "";
|
const nurA = creator ? " AND (a.creator_id = ? OR a.verantwortlich_id = ?)" : "";
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
import express from "express";
|
import express from "express";
|
||||||
import {
|
import {
|
||||||
db, protokolliere, echteIp, sitzungLesen, personAnlegen, betreuungSetzen, istLeitung, istDogFather, siehtAlles, pipelineIds,
|
db, protokolliere, echteIp, sitzungLesen, personAnlegen, betreuungSetzen, istLeitung, istDogFather, siehtAlles, pipelineIds,
|
||||||
|
heuteLokal,
|
||||||
} from "./workspace.js";
|
} from "./workspace.js";
|
||||||
|
|
||||||
export const scoutRouter = express.Router();
|
export const scoutRouter = express.Router();
|
||||||
@@ -131,7 +132,9 @@ const VERBUND = `
|
|||||||
scoutRouter.get("/workspace/api/leads", (req, res) => {
|
scoutRouter.get("/workspace/api/leads", (req, res) => {
|
||||||
try {
|
try {
|
||||||
const { wo, werte } = sichtbar(req.sicht || req.person);
|
const { wo, werte } = sichtbar(req.sicht || req.person);
|
||||||
const heute = jetzt().slice(0, 10);
|
/* ORTSZEIT (01.10.2026), nicht der UTC-Tag: Sonst gilt ein Lead
|
||||||
|
nachts zwischen 00:00 und 02:00 als einen Tag juenger. */
|
||||||
|
const heute = heuteLokal();
|
||||||
res.json({
|
res.json({
|
||||||
stufen: STUFEN,
|
stufen: STUFEN,
|
||||||
/* Die Auswahllisten kommen MIT, damit die Oberflaeche keine
|
/* Die Auswahllisten kommen MIT, damit die Oberflaeche keine
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ import express from "express";
|
|||||||
import {
|
import {
|
||||||
db, sitzungLesen, protokolliere, echteIp,
|
db, sitzungLesen, protokolliere, echteIp,
|
||||||
TREFF_BRETTER, TREFF_ROLLEN, ROLLEN_NAME, istHand,
|
TREFF_BRETTER, TREFF_ROLLEN, ROLLEN_NAME, istHand,
|
||||||
|
heuteLokal,
|
||||||
} from "./workspace.js";
|
} from "./workspace.js";
|
||||||
/* Die Tabellen und die Sperrfrage stehen in einem Blatt ohne eigene
|
/* Die Tabellen und die Sperrfrage stehen in einem Blatt ohne eigene
|
||||||
Importe -- workspace.js braucht beides ebenfalls, und ein Importkreis
|
Importe -- workspace.js braucht beides ebenfalls, und ein Importkreis
|
||||||
@@ -1023,7 +1024,8 @@ treffRouter.post("/workspace/api/treff/mitmachen/:id/uebernehmen", gleicheHerkun
|
|||||||
.run(
|
.run(
|
||||||
`${wer?.name ?? "Jemand"} hat sich im Rudel gemeldet`,
|
`${wer?.name ?? "Jemand"} hat sich im Rudel gemeldet`,
|
||||||
`Aus „Mitmachen": ${String(e.titel ?? "")}\n\n${String(e.text ?? "")}`.trim(),
|
`Aus „Mitmachen": ${String(e.titel ?? "")}\n\n${String(e.text ?? "")}`.trim(),
|
||||||
nun.slice(0, 10), e.erstellt_von, nun, req.person.id, "Das Rudel");
|
/* Der TAG in Ortszeit (01.10.2026), der Zeitstempel in UTC. */
|
||||||
|
heuteLokal(), e.erstellt_von, nun, req.person.id, "Das Rudel");
|
||||||
protokolliere("treff_talent", { personId: req.person.id, ip: echteIp(req),
|
protokolliere("treff_talent", { personId: req.person.id, ip: echteIp(req),
|
||||||
detail: `aus Eintrag ${id}` });
|
detail: `aus Eintrag ${id}` });
|
||||||
res.json({ ok: true, talent_id: Number(r.lastInsertRowid) });
|
res.json({ ok: true, talent_id: Number(r.lastInsertRowid) });
|
||||||
|
|||||||
@@ -39,6 +39,7 @@
|
|||||||
import express from "express";
|
import express from "express";
|
||||||
import {
|
import {
|
||||||
db, protokolliere, echteIp, istDogFather, heuteLokal,
|
db, protokolliere, echteIp, istDogFather, heuteLokal,
|
||||||
|
tagLokal,
|
||||||
} from "./workspace.js";
|
} from "./workspace.js";
|
||||||
import { UNTERSTUETZUNG_ARTEN, ZAEHLUNG_TAGE } from "./unterstuetzung-tabellen.js";
|
import { UNTERSTUETZUNG_ARTEN, ZAEHLUNG_TAGE } from "./unterstuetzung-tabellen.js";
|
||||||
|
|
||||||
@@ -358,8 +359,11 @@ unterstuetzungRouter.delete("/workspace/api/unterstuetzung/:id(\\d+)",
|
|||||||
* hinsieht. */
|
* hinsieht. */
|
||||||
export function unterstuetzungAufraeumen() {
|
export function unterstuetzungAufraeumen() {
|
||||||
try {
|
try {
|
||||||
const grenze = new Date(Date.now() - ZAEHLUNG_TAGE * 86400000)
|
/* ORTSZEIT (01.10.2026): Die Tage in dieser Tabelle stehen in
|
||||||
.toISOString().slice(0, 10);
|
Ortszeit, die Grenze stand in UTC. Nachts wurde dadurch ein Tag
|
||||||
|
zu wenig geraeumt -- kein Schaden, aber zwei Rechnungen fuer
|
||||||
|
denselben Begriff, und eine davon laeuft irgendwann weg. */
|
||||||
|
const grenze = tagLokal(-ZAEHLUNG_TAGE);
|
||||||
const r = db().prepare("DELETE FROM unterstuetzung_striche WHERE tag < ?").run(grenze);
|
const r = db().prepare("DELETE FROM unterstuetzung_striche WHERE tag < ?").run(grenze);
|
||||||
return r.changes || 0;
|
return r.changes || 0;
|
||||||
} catch { return 0; }
|
} catch { return 0; }
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ import { mkdirSync, writeFileSync, unlinkSync } from "node:fs";
|
|||||||
import {
|
import {
|
||||||
db, protokolliere, echteIp, sitzungLesen, DATEN_ORDNER,
|
db, protokolliere, echteIp, sitzungLesen, DATEN_ORDNER,
|
||||||
KANAELE, kanalVonHandle, TREFF_BRETTER,
|
KANAELE, kanalVonHandle, TREFF_BRETTER,
|
||||||
|
heuteLokal,
|
||||||
} from "./workspace.js";
|
} from "./workspace.js";
|
||||||
import { darfSchreiben, sofortFreigeben } from "./workspace-treff.js";
|
import { darfSchreiben, sofortFreigeben } from "./workspace-treff.js";
|
||||||
import { sichtbar } from "./workspace-bereiche.js";
|
import { sichtbar } from "./workspace-bereiche.js";
|
||||||
@@ -282,7 +283,10 @@ videoRouter.post("/workspace/api/bereich/:bereich/video", async (req, res) => {
|
|||||||
(bereich, art, titel, datum, status, erstellt, erstellt_von,
|
(bereich, art, titel, datum, status, erstellt, erstellt_von,
|
||||||
quelle_url, quelle_kanal, quelle_geholt_am, aus_eintrag_id)
|
quelle_url, quelle_kanal, quelle_geholt_am, aus_eintrag_id)
|
||||||
VALUES (?,?,?,?, 'offen', ?,?,?,?,?,?)`)
|
VALUES (?,?,?,?, 'offen', ?,?,?,?,?,?)`)
|
||||||
.run(bereich, arten[bereich] || "clip", auskunft.titel, jetzt.slice(0, 10),
|
/* Der TAG in Ortszeit (01.10.2026), der Zeitstempel daneben in
|
||||||
|
UTC -- ein Zeitpunkt ist ueberall derselbe, ein Kalendertag
|
||||||
|
nicht. */
|
||||||
|
.run(bereich, arten[bereich] || "clip", auskunft.titel, heuteLokal(),
|
||||||
jetzt, req.person.id, url, ablage, jetzt, ausQuelle ? aus : null);
|
jetzt, req.person.id, url, ablage, jetzt, ausQuelle ? aus : null);
|
||||||
eintragId = Number(lastInsertRowid);
|
eintragId = Number(lastInsertRowid);
|
||||||
}
|
}
|
||||||
@@ -434,7 +438,8 @@ export async function videoNochDa(url) {
|
|||||||
export async function videoWacheLauf() {
|
export async function videoWacheLauf() {
|
||||||
const d = db();
|
const d = db();
|
||||||
const grenze = new Date(Date.now() - WACHE_ABSTAND_TAGE * 86400_000).toISOString();
|
const grenze = new Date(Date.now() - WACHE_ABSTAND_TAGE * 86400_000).toISOString();
|
||||||
const heute = new Date().toISOString().slice(0, 10);
|
/* ORTSZEIT (01.10.2026) -- nicht der UTC-Tag. */
|
||||||
|
const heute = heuteLokal();
|
||||||
|
|
||||||
/* WELCHE ZUERST: die mit Fehlversuchen (die sind verdaechtig und
|
/* WELCHE ZUERST: die mit Fehlversuchen (die sind verdaechtig und
|
||||||
sollen schnell geklaert sein), dann die am laengsten ungesehenen.
|
sollen schnell geklaert sein), dann die am laengsten ungesehenen.
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ import {
|
|||||||
darfSchreibenMit,
|
darfSchreibenMit,
|
||||||
KATALOG_EMPFAENGER,
|
KATALOG_EMPFAENGER,
|
||||||
KATALOG_EMPFAENGER_SQL,
|
KATALOG_EMPFAENGER_SQL,
|
||||||
|
heuteLokal,
|
||||||
} from "./workspace.js";
|
} from "./workspace.js";
|
||||||
|
|
||||||
/* Dieselbe Meldung wie beim anderen Bewerbungsweg -- eine Stelle,
|
/* Dieselbe Meldung wie beim anderen Bewerbungsweg -- eine Stelle,
|
||||||
@@ -2036,7 +2037,10 @@ vorlagenRouter.post("/workspace/api/vorlagen/uebernehmen", gleicheHerkunft,
|
|||||||
(bereich, art, titel, text, datum, status, creator_id, hook, format,
|
(bereich, art, titel, text, datum, status, creator_id, hook, format,
|
||||||
erstellt, erstellt_von)
|
erstellt, erstellt_von)
|
||||||
VALUES (?,?,?,?,?,?,?,?,?,?,?)`)
|
VALUES (?,?,?,?,?,?,?,?,?,?,?)`)
|
||||||
.run(bereich, unterart, titel, text, jetzt().slice(0, 10), "offen",
|
/* Der TAG in Ortszeit (01.10.2026), der Zeitstempel weiter
|
||||||
|
unten in UTC. Aus dem Startkatalog angelegte Eintraege
|
||||||
|
trugen sonst nachts das Datum von gestern. */
|
||||||
|
.run(bereich, unterart, titel, text, heuteLokal(), "offen",
|
||||||
creatorId, zusatz.hook || null, zusatz.format || null,
|
creatorId, zusatz.hook || null, zusatz.format || null,
|
||||||
jetzt(), req.person.id);
|
jetzt(), req.person.id);
|
||||||
angelegt.push(titel);
|
angelegt.push(titel);
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ import {
|
|||||||
db, protokolliere, echteIp, darfAufgabenVerteilen, entscheidetUeberAufgaben,
|
db, protokolliere, echteIp, darfAufgabenVerteilen, entscheidetUeberAufgaben,
|
||||||
istDogFather, istHand,
|
istDogFather, istHand,
|
||||||
sitzungLesen,
|
sitzungLesen,
|
||||||
|
heuteLokal,
|
||||||
} from "./workspace.js";
|
} from "./workspace.js";
|
||||||
import { TEAM_DOGI_ROLLEN } from "./crew-adresse.js";
|
import { TEAM_DOGI_ROLLEN } from "./crew-adresse.js";
|
||||||
/* WER ES ERFAEHRT -- an einer Stelle fuer beide Bewerbungswege.
|
/* WER ES ERFAEHRT -- an einer Stelle fuer beide Bewerbungswege.
|
||||||
@@ -920,7 +921,11 @@ export function resuemeeFuer(personId) {
|
|||||||
zeilen.push({ zustand, bewertung: null, frist: a.frist, aufgabe_status: a.status });
|
zeilen.push({ zustand, bewertung: null, frist: a.frist, aufgabe_status: a.status });
|
||||||
}
|
}
|
||||||
|
|
||||||
const heute = new Date().toISOString().slice(0, 10);
|
/* ORTSZEIT (01.10.2026): Mit dem UTC-Tag galt eine Aufgabe, deren
|
||||||
|
Frist gestern ablief, nachts zwischen 00:00 und 02:00 noch als
|
||||||
|
puenktlich -- und die Zahl „ueberfaellig" war zwei Stunden lang
|
||||||
|
zu niedrig. */
|
||||||
|
const heute = heuteLokal();
|
||||||
const zaehl = { offen: 0, angenommen: 0, arbeit: 0, erledigt: 0, abgelehnt: 0 };
|
const zaehl = { offen: 0, angenommen: 0, arbeit: 0, erledigt: 0, abgelehnt: 0 };
|
||||||
let ueberfaellig = 0, gelobt = 0, zuVerbessern = 0;
|
let ueberfaellig = 0, gelobt = 0, zuVerbessern = 0;
|
||||||
for (const z of zeilen) {
|
for (const z of zeilen) {
|
||||||
|
|||||||
Reference in New Issue
Block a user