diff --git a/server/pruef-anruf.mjs b/server/pruef-anruf.mjs index 027a2300..6146f8e1 100644 --- a/server/pruef-anruf.mjs +++ b/server/pruef-anruf.mjs @@ -28,6 +28,10 @@ process.env.WORKSPACE_DB = join(ordner, "workspace.db"); process.env.PORT = String(PORT); process.env.SITE_ACCESS_SECRET = "lokaler-test"; process.env.SITE_PUBLIC_LAUNCH_AT = "2020-01-01T00:00:00+01:00"; +/* Zwei Sekunden statt zwei Minuten -- sonst muesste Abschnitt 5e so + lange warten, und eine Pruefung, die zwei Minuten braucht, wird + abgeschaltet. Im Betrieb steht die Variable nirgends. */ +process.env.ANRUF_KLINGELT_SEKUNDEN = "2"; /* Der Vermittlungsserver holt sein Geheimnis aus einer Datei. Hier muss der Pfad UMGEBOGEN werden, bevor index.js geladen wird -- sonst zeigte er auf die echte Datei unter /etc, und die Pruefung wuerde @@ -267,6 +271,61 @@ melde("=== 5. Auflegen ==="); jetzt in `pushTextFuer()` -- eine Zeile weniger Verschachtelung und eine Frage, die sich beantworten laesst. ======================================================================= */ +/* ======================================================================= + 5e. EIN VERPASSTER ANRUF HINTERLAESST EINE SPUR + + Bisher verschwand er lautlos. Wer zu spaet kam, oeffnete den Chat + und sah -- nichts. Keine Zeile, kein Hinweis, nicht einmal, DASS + jemand angerufen hat. + + Genau das fuehlt sich an wie „es geht einfach nicht", auch wenn + technisch alles funktioniert hat: Der Anruf kam an, es klingelte, + niemand war schnell genug, und danach war es, als waere nie etwas + gewesen. Jedes Telefon der Welt zeigt einen verpassten Anruf. + ======================================================================= */ +melde(""); +melde("=== 5e. Ein verpasster Anruf ==="); +{ + const raum = json(await roh("/workspace/api/chat/raeume", HAUS, + { cookie: kDogi })).raeume?.[0]; + if (!raum) { + unklar("kein Gespraech vorhanden -- nicht nachgesehen"); + } else { + const vorher = json(await roh(`/workspace/api/chat/raeume/${raum.id}/nachrichten`, HAUS, + { cookie: kDogi })).nachrichten?.length ?? 0; + + const start = await roh(`/workspace/api/anruf/${raum.id}/start`, HAUS, + { cookie: kDogi }, { video: false }); + ok(start.code === 200 || start.code === 201, `Anruf gestartet (${start.code})`); + + /* Niemand geht ran. Nach ANRUF_KLINGELT_SEKUNDEN (hier 2) gilt er + als verpasst -- `aufraeumen()` laeuft bei der naechsten Anfrage + mit. */ + await new Promise((r) => setTimeout(r, 2600)); + await roh("/workspace/api/anruf/offen", CREW, { cookie: kHand }); + + const nachher = json(await roh(`/workspace/api/chat/raeume/${raum.id}/nachrichten`, HAUS, + { cookie: kDogi })).nachrichten || []; + ok(nachher.length === vorher + 1, + `es steht genau EINE neue Zeile im Gespraech (${vorher} -> ${nachher.length})`); + const letzte = nachher[nachher.length - 1]; + ok(/[Vv]erpasst/.test(letzte?.text || ""), + `und sie sagt, was los war („${letzte?.text}")`); + ok(letzte?.von_id !== undefined, + "sie steht beim Anrufer, nicht als Systemtext ohne Absender"); + + /* UND NICHT ZWEIMAL. `aufraeumen()` laeuft bei JEDER Anfrage -- + ohne das Loeschen aus `laufend` staende hier bei jedem Aufruf + eine weitere Zeile. */ + await roh("/workspace/api/anruf/offen", CREW, { cookie: kHand }); + await roh("/workspace/api/anruf/offen", CREW, { cookie: kHand }); + const nochmal = json(await roh(`/workspace/api/chat/raeume/${raum.id}/nachrichten`, HAUS, + { cookie: kDogi })).nachrichten || []; + ok(nochmal.length === nachher.length, + `und bleibt bei einer, auch nach weiteren Abfragen (${nochmal.length})`); + } +} + melde(""); melde("=== 5d. Was in der Benachrichtigung steht ==="); { diff --git a/server/workspace-anruf.js b/server/workspace-anruf.js index b48d5e9a..f9368289 100644 --- a/server/workspace-anruf.js +++ b/server/workspace-anruf.js @@ -91,8 +91,33 @@ export const GRUPPE_MAX = 4; * * Ohne diese Grenze bliebe ein Anruf, bei dem der Anrufer die Seite * schließt, für immer offen stehen -- und der Angerufene sähe eine - * Einladung zu einem Gespräch, an dem niemand mehr teilnimmt. */ -const KLINGELT_SEKUNDEN = 45; + * Einladung zu einem Gespräch, an dem niemand mehr teilnimmt. + * + * --------------------------------------------------------------------- + * WARUM ZWEI MINUTEN UND NICHT 45 SEKUNDEN (18.09.2026) + * + * Filipe: „das mit dem anruf klappt nicht … es geeeeeht einfach + * nicht." Nachgemessen war serverseitig alles in Ordnung: Der Anruf + * kam an, der Raum stimmte, die Angerufene war angemeldet und hatte + * ein Gerät für Benachrichtigungen. + * + * Nur passte die Zeit nicht zum Weg. Bei einem Telefon hebt man ab -- + * hier muss in dieselben Sekunden: Benachrichtigung zustellen, sie + * bemerken, Handy entsperren, antippen, App laden, Anmeldung prüfen. + * 45 Sekunden reichen dafür, wenn man das Gerät in der Hand hält, und + * sonst nie. + * + * Das ist der Unterschied zwischen „funktioniert" und „funktioniert + * im Alltag". Zwei Minuten sind lang genug, um aus der Tasche zu + * kommen, und kurz genug, dass niemand vor einem Anruf sitzt, den es + * längst nicht mehr gibt. */ +const KLINGELT_SEKUNDEN = Number(process.env.ANRUF_KLINGELT_SEKUNDEN) || 120; + +/* WARUM UEBER DIE UMGEBUNG UMSTELLBAR: Damit eine Pruefung den Ablauf + messen kann, ohne zwei Minuten zu warten. Eine Pruefung, die so + lange braucht, wird abgeschaltet -- und dann ist der verpasste + Anruf wieder ungeprueft. Im Betrieb steht die Variable nirgends; + dort gelten die 120 Sekunden. */ /* Wer gerade in welchem Raum telefoniert. IM SPEICHER, NICHT IN DER DATENBANK: Ein laufender Anruf ist ein @@ -112,10 +137,58 @@ function aufraeumen() { ist keiner mehr -- der Angerufene ist nicht rangegangen. */ if (a.wer.size === 1 && jetzt - a.seit > KLINGELT_SEKUNDEN * 1000) { laufend.delete(raumId); + + /* ---- UND ER HINTERLAESST EINE SPUR (18.09.2026) ------------- + + Bisher verschwand ein verpasster Anruf lautlos. Wer zu spaet + kam, oeffnete den Chat und sah -- nichts. Keine Zeile, kein + Hinweis, nicht einmal, DASS jemand angerufen hat. Genau das + fuehlt sich an wie „es geht einfach nicht", auch wenn technisch + alles funktioniert hat. + + Jedes Telefon der Welt zeigt einen verpassten Anruf. Hier + steht er als Zeile im Gespraech, mit Namen und Uhrzeit -- und + damit hat der andere etwas, worauf er antworten kann. + + IN EINEM EIGENEN try: Ein Fehler beim Schreiben der Zeile darf + das Aufraeumen nicht anhalten -- sonst bliebe ein abgelaufener + Anruf stehen, und das waere schlimmer als eine fehlende + Notiz. */ + try { verpasstVermerken(raumId, a); } catch (f) { + console.error("[anruf] verpasst:", f?.message); + } } } } +/** Schreibt „Verpasster Anruf" in das Gespraech. + * + * Als ganz normale Nachricht des Anrufers: So steht sie an der + * richtigen Stelle im Verlauf, wird mitgezaehlt wie jede andere und + * braucht keine Sonderbehandlung in der Oberflaeche. */ +function verpasstVermerken(raumId, a) { + const anrufer = [...a.wer.entries()][0]; + if (!anrufer) return; + const [id, wer] = anrufer; + const d = db(); + const n = new Date().toISOString(); + const text = a.video ? "📞 Verpasster Videoanruf" : "📞 Verpasster Anruf"; + d.prepare("INSERT INTO chat_nachrichten (raum_id, person_id, text, erstellt) VALUES (?,?,?,?)") + .run(raumId, id, text, n); + const neueId = d.prepare("SELECT last_insert_rowid() AS id").get().id; + d.prepare("UPDATE chat_raeume SET letzte_am = ? WHERE id = ?").run(n, raumId); + + /* Die anderen im Raum bekommen sie wie jede Nachricht -- inklusive + Benachrichtigung, falls sie gerade nicht zusehen. Wer den Anruf + verpasst hat, sieht wenigstens, DASS er ihn verpasst hat. */ + const andere = teilnehmerFuerAnruf(raumId) + .map((t) => t.id).filter((x) => x !== id); + chatEreignis(raumId, { + id: neueId, raum_id: raumId, von_id: id, von: wer.name, + text, erstellt: n, zurueckgenommen: false, antwort: null, anhang: null, + }, andere, "neu"); +} + function angemeldet(req, res, next) { const person = sitzungLesen(req); if (!person) return res.status(401).json({ fehler: "nicht_angemeldet" }); diff --git a/workspace/app.webmanifest b/workspace/app.webmanifest index 51957fe9..020af340 100644 --- a/workspace/app.webmanifest +++ b/workspace/app.webmanifest @@ -22,25 +22,25 @@ }, "icons": [ { - "src": "/assets/img/app-symbole/workspace-192.png?v=202609182254", + "src": "/assets/img/app-symbole/workspace-192.png?v=202609182330", "sizes": "192x192", "type": "image/png", "purpose": "any" }, { - "src": "/assets/img/app-symbole/workspace-512.png?v=202609182254", + "src": "/assets/img/app-symbole/workspace-512.png?v=202609182330", "sizes": "512x512", "type": "image/png", "purpose": "any" }, { - "src": "/assets/img/app-symbole/workspace-192-maskable.png?v=202609182254", + "src": "/assets/img/app-symbole/workspace-192-maskable.png?v=202609182330", "sizes": "192x192", "type": "image/png", "purpose": "maskable" }, { - "src": "/assets/img/app-symbole/workspace-512-maskable.png?v=202609182254", + "src": "/assets/img/app-symbole/workspace-512-maskable.png?v=202609182330", "sizes": "512x512", "type": "image/png", "purpose": "maskable" diff --git a/workspace/aufgaben.html b/workspace/aufgaben.html index a51e7dae..087df9b7 100644 --- a/workspace/aufgaben.html +++ b/workspace/aufgaben.html @@ -12,19 +12,19 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - + + + + + + - + @@ -291,10 +291,10 @@ - - - - - + + + + + diff --git a/workspace/automation.html b/workspace/automation.html index cdf25624..b5db26bb 100644 --- a/workspace/automation.html +++ b/workspace/automation.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -168,10 +168,10 @@ - - - - - + + + + + diff --git a/workspace/befinden.html b/workspace/befinden.html index 9123c954..b5d1face 100644 --- a/workspace/befinden.html +++ b/workspace/befinden.html @@ -7,14 +7,14 @@ - - - - - - - - + + + + + + + + @@ -105,9 +105,9 @@ - - - - + + + + diff --git a/workspace/bereich.html b/workspace/bereich.html index 218e8570..3339637e 100644 --- a/workspace/bereich.html +++ b/workspace/bereich.html @@ -12,24 +12,24 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - + + + + + + - - + + - + @@ -251,14 +251,14 @@ - - - - - - - - - + + + + + + + + + diff --git a/workspace/bewerben.html b/workspace/bewerben.html index 9115d3b0..055c96da 100644 --- a/workspace/bewerben.html +++ b/workspace/bewerben.html @@ -7,17 +7,17 @@ - - - - - - - - - + + + + + + + + + - + @@ -108,10 +108,10 @@ - - - - - + + + + + diff --git a/workspace/bewerbungen.html b/workspace/bewerbungen.html index c4aa1fc8..4cda9dc2 100644 --- a/workspace/bewerbungen.html +++ b/workspace/bewerbungen.html @@ -7,16 +7,16 @@ - - - - - - - - + + + + + + + + - + @@ -80,10 +80,10 @@ - - - - - + + + + + diff --git a/workspace/calls.html b/workspace/calls.html index d4075271..599554be 100644 --- a/workspace/calls.html +++ b/workspace/calls.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -89,11 +89,11 @@ - - - - - - + + + + + + diff --git a/workspace/chat.html b/workspace/chat.html index ba895fad..d124a10d 100644 --- a/workspace/chat.html +++ b/workspace/chat.html @@ -12,26 +12,26 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - + + + + - - - + + + - + @@ -341,15 +341,15 @@ - - - - + + + + - - + + diff --git a/workspace/content.html b/workspace/content.html index 7a79122b..e60a0a26 100644 --- a/workspace/content.html +++ b/workspace/content.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -179,12 +179,12 @@ - - - - - - - + + + + + + + diff --git a/workspace/crew-index.html b/workspace/crew-index.html index 83595de2..07efdc27 100644 --- a/workspace/crew-index.html +++ b/workspace/crew-index.html @@ -36,15 +36,15 @@ - - - + + + - + @@ -339,6 +339,6 @@ - + diff --git a/workspace/crew.webmanifest b/workspace/crew.webmanifest index 8ec7fea3..7026f8cc 100644 --- a/workspace/crew.webmanifest +++ b/workspace/crew.webmanifest @@ -22,25 +22,25 @@ }, "icons": [ { - "src": "/assets/img/app-symbole/crew-192.png?v=202609182254", + "src": "/assets/img/app-symbole/crew-192.png?v=202609182330", "sizes": "192x192", "type": "image/png", "purpose": "any" }, { - "src": "/assets/img/app-symbole/crew-512.png?v=202609182254", + "src": "/assets/img/app-symbole/crew-512.png?v=202609182330", "sizes": "512x512", "type": "image/png", "purpose": "any" }, { - "src": "/assets/img/app-symbole/crew-192-maskable.png?v=202609182254", + "src": "/assets/img/app-symbole/crew-192-maskable.png?v=202609182330", "sizes": "192x192", "type": "image/png", "purpose": "maskable" }, { - "src": "/assets/img/app-symbole/crew-512-maskable.png?v=202609182254", + "src": "/assets/img/app-symbole/crew-512-maskable.png?v=202609182330", "sizes": "512x512", "type": "image/png", "purpose": "maskable" diff --git a/workspace/dateien.html b/workspace/dateien.html index e62f3d4c..5f894ba1 100644 --- a/workspace/dateien.html +++ b/workspace/dateien.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -108,10 +108,10 @@ - - - - - + + + + + diff --git a/workspace/entwicklung.html b/workspace/entwicklung.html index 9618a15a..f5008544 100644 --- a/workspace/entwicklung.html +++ b/workspace/entwicklung.html @@ -7,14 +7,14 @@ - - - - - - - - + + + + + + + + @@ -102,9 +102,9 @@ - - - - + + + + diff --git a/workspace/index.html b/workspace/index.html index bb23cb96..0c6b8b4a 100644 --- a/workspace/index.html +++ b/workspace/index.html @@ -30,9 +30,9 @@ - - - + + + @@ -401,6 +401,6 @@ - + diff --git a/workspace/kalender.html b/workspace/kalender.html index 353cda8e..858b62b1 100644 --- a/workspace/kalender.html +++ b/workspace/kalender.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -377,11 +377,11 @@ - - - - - - + + + + + + diff --git a/workspace/leistung.html b/workspace/leistung.html index 0b0672dd..9f804f11 100644 --- a/workspace/leistung.html +++ b/workspace/leistung.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -444,10 +444,10 @@ - - - - - + + + + + diff --git a/workspace/personen.html b/workspace/personen.html index 84da6289..c0e5a27d 100644 --- a/workspace/personen.html +++ b/workspace/personen.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -423,10 +423,10 @@ - - - - - + + + + + diff --git a/workspace/profil.html b/workspace/profil.html index f4572a33..27ff14c8 100644 --- a/workspace/profil.html +++ b/workspace/profil.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -214,11 +214,11 @@ - - - - - - + + + + + + diff --git a/workspace/rechte.html b/workspace/rechte.html index 7fe147e8..86e097b3 100644 --- a/workspace/rechte.html +++ b/workspace/rechte.html @@ -7,14 +7,14 @@ - - - - - - - - + + + + + + + + @@ -134,9 +134,9 @@ Beim ersten Anlauf fehlte die Zeile auf genau diesen beiden neuen Seiten. Gefunden hat das nicht das Auge, sondern pruef-css-klassen, die seit dem 07.09. jede Seite danach absucht. --> - - - - + + + + diff --git a/workspace/report.html b/workspace/report.html index cae79a6f..28c770ed 100644 --- a/workspace/report.html +++ b/workspace/report.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -106,11 +106,11 @@ - - - - - - + + + + + + diff --git a/workspace/scouting.html b/workspace/scouting.html index 4e8ca00d..f805334c 100644 --- a/workspace/scouting.html +++ b/workspace/scouting.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -173,10 +173,10 @@ - - - - - + + + + + diff --git a/workspace/start.html b/workspace/start.html index 3b792967..45feb20e 100644 --- a/workspace/start.html +++ b/workspace/start.html @@ -12,21 +12,21 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - + + + + - - + + - + @@ -678,10 +678,10 @@

- - - - - + + + + + diff --git a/workspace/startcheck.html b/workspace/startcheck.html index f58898d2..b8c51663 100644 --- a/workspace/startcheck.html +++ b/workspace/startcheck.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -85,11 +85,11 @@ - - - - - - + + + + + + diff --git a/workspace/steckbrief.html b/workspace/steckbrief.html index cea5b780..cf58b649 100644 --- a/workspace/steckbrief.html +++ b/workspace/steckbrief.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -146,11 +146,11 @@ - - - - - - + + + + + + diff --git a/workspace/talente.html b/workspace/talente.html index 28817fca..f0087459 100644 --- a/workspace/talente.html +++ b/workspace/talente.html @@ -7,18 +7,18 @@ - - - - - - + + + + + + - - - + + + @@ -111,9 +111,9 @@ - - - - + + + + diff --git a/workspace/team.html b/workspace/team.html index e7fd3751..7b58c60c 100644 --- a/workspace/team.html +++ b/workspace/team.html @@ -7,20 +7,20 @@ - - - - - - - + + + + + + + - + @@ -110,10 +110,10 @@ - - - - - + + + + + diff --git a/workspace/teamlage.html b/workspace/teamlage.html index 4f80ec51..0c2b4d46 100644 --- a/workspace/teamlage.html +++ b/workspace/teamlage.html @@ -7,20 +7,20 @@ - - - - - - - + + + + + + + - + - - - - + + + + diff --git a/workspace/teilen.html b/workspace/teilen.html index 2f22e31e..7106e0e2 100644 --- a/workspace/teilen.html +++ b/workspace/teilen.html @@ -7,13 +7,13 @@ - - - - - - - + + + + + + + @@ -112,9 +112,9 @@ - - - - + + + + diff --git a/workspace/treff-moderation.html b/workspace/treff-moderation.html index fc0e1644..aee03b66 100644 --- a/workspace/treff-moderation.html +++ b/workspace/treff-moderation.html @@ -7,14 +7,14 @@ - - - - - - - - + + + + + + + + @@ -126,9 +126,9 @@ - - - - + + + + diff --git a/workspace/treff-regeln.html b/workspace/treff-regeln.html index 5c9798af..f0f99e57 100644 --- a/workspace/treff-regeln.html +++ b/workspace/treff-regeln.html @@ -7,18 +7,18 @@ - - - - - - - + + + + + + + - + @@ -221,10 +221,10 @@ Beim ersten Anlauf fehlte die Zeile auf genau diesen beiden neuen Seiten. Gefunden hat das nicht das Auge, sondern pruef-css-klassen, die seit dem 07.09. jede Seite danach absucht. --> - - - - - + + + + + diff --git a/workspace/uebersicht.html b/workspace/uebersicht.html index 24e67bc0..acd62aab 100644 --- a/workspace/uebersicht.html +++ b/workspace/uebersicht.html @@ -12,22 +12,22 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - + + + + - - - + + + - + @@ -149,11 +149,11 @@ - + - - - - + + + + diff --git a/workspace/wissen.html b/workspace/wissen.html index b1f60d3c..f4872919 100644 --- a/workspace/wissen.html +++ b/workspace/wissen.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -190,10 +190,10 @@ - - - - - + + + + +