diff --git a/server/pruef-anruf.mjs b/server/pruef-anruf.mjs index 2782cbac..63780a22 100644 --- a/server/pruef-anruf.mjs +++ b/server/pruef-anruf.mjs @@ -289,6 +289,59 @@ melde("=== 5. Auflegen ==="); niemand war schnell genug, und danach war es, als waere nie etwas gewesen. Jedes Telefon der Welt zeigt einen verpassten Anruf. ======================================================================= */ +/* ======================================================================= + 5f. UND EIN GEFUEHRTER ANRUF -- MIT DAUER + + Filipe: „im chat soll auch stehen verpasster anruf oder anruf + gehabt und wie lange." + + Die zweite Haelfte. Ein verpasster Anruf steht seit heute im Chat; + ein GEFUEHRTER stand nirgends -- nach dem Auflegen war das Gespraech + spurlos weg. Tage spaeter ist die Frage aber nicht „hat er + angerufen", sondern „haben wir das besprochen oder nur kurz + telefoniert?". Drei Minuten sind ein Gespraech, zwoelf Sekunden + sind ein Verwaehlen. + ======================================================================= */ +melde(""); +melde("=== 5f. Ein gefuehrter 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; + + await roh(`/workspace/api/anruf/${raum.id}/start`, HAUS, { cookie: kDogi }, { video: false }); + const dabei = await roh(`/workspace/api/anruf/${raum.id}/dabei`, CREW, { cookie: kHand }, {}); + ok(dabei.code === 200, `die rechte Hand geht ran (${dabei.code})`); + + /* Kurz reden, dann auflegen -- beide. */ + await new Promise((r) => setTimeout(r, 1500)); + await roh(`/workspace/api/anruf/${raum.id}/ende`, CREW, { cookie: kHand }, {}); + await roh(`/workspace/api/anruf/${raum.id}/ende`, HAUS, { cookie: kDogi }, {}); + + const nachher = json(await roh(`/workspace/api/chat/raeume/${raum.id}/nachrichten`, HAUS, + { cookie: kDogi })).nachrichten || []; + ok(nachher.length === vorher + 1, + `es steht eine Zeile im Gespraech (${vorher} -> ${nachher.length})`); + + const letzte = nachher[nachher.length - 1]; + ok(/Anruf/.test(letzte?.text || "") && !/[Vv]erpasst/.test(letzte?.text || ""), + `und sie sagt „Anruf", nicht „verpasst" („${letzte?.text}")`); + ok(/Sekunde|:\d\d/.test(letzte?.text || ""), + `mit Dauer („${letzte?.text}")`); + + /* DIE DAUER ZAEHLT AB DEM RANGEHEN. Gezaehlt wurde hier rund + anderthalb Sekunden -- stuende dort die Zeit seit dem Klingeln, + waere es deutlich mehr. Die Pruefung bleibt grosszuegig: Sie + misst, dass es SEKUNDEN sind und keine Minuten. */ + ok(/Sekunde/.test(letzte?.text || ""), + "und zwar ab dem Rangehen, nicht ab dem Klingeln"); + } +} + melde(""); melde("=== 5e. Ein verpasster Anruf ==="); { diff --git a/server/workspace-anruf.js b/server/workspace-anruf.js index f9368289..76bc18ec 100644 --- a/server/workspace-anruf.js +++ b/server/workspace-anruf.js @@ -161,6 +161,49 @@ function aufraeumen() { } } +/** Schreibt „Anruf · 3:42" in das Gespraech, wenn er vorbei ist. + * + * Filipe: „im chat soll auch stehen verpasster anruf oder anruf + * gehabt und wie lange." + * + * WARUM DIE DAUER UND NICHT NUR „Anruf": Eine Zeile ohne Zahl + * beantwortet die Frage nicht, die man Tage spaeter hat -- „haben wir + * das besprochen oder nur kurz telefoniert?". Drei Minuten sind ein + * Gespraech, zwoelf Sekunden sind ein Verwaehlen. + * + * GEZAEHLT AB DEM RANGEHEN, nicht ab dem Klingeln. Sonst staende bei + * jedem Anruf eine halbe Minute zu viel darin -- die Zeit, in der das + * Telefon nur laeutete. + */ +function anrufVermerken(raumId, a) { + const beginn = a.gespraechSeit || a.seit; + const s = Math.max(1, Math.round((Date.now() - beginn) / 1000)); + /* Unter einer Minute reicht die Sekundenzahl -- „0:07" liest sich + umstaendlicher als „7 Sekunden". */ + const dauer = s < 60 + ? `${s} Sekunde${s === 1 ? "" : "n"}` + : `${Math.floor(s / 60)}:${String(s % 60).padStart(2, "0")} Minuten`; + + /* Die Zeile steht beim ANRUFER -- er hat den Anruf begonnen, und im + Verlauf liest es sich wie bei jedem Telefon. Wer das war, weiss + nur der Eintrag selbst; `wer` ist nach Reihenfolge des Beitritts + sortiert. */ + const wer = a.anrufer || null; + if (!wer) return; + const d = db(); + const n = new Date().toISOString(); + const text = `📞 ${a.video ? "Videoanruf" : "Anruf"} · ${dauer}`; + d.prepare("INSERT INTO chat_nachrichten (raum_id, person_id, text, erstellt) VALUES (?,?,?,?)") + .run(raumId, wer.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); + + chatEreignis(raumId, { + id: neueId, raum_id: raumId, von_id: wer.id, von: wer.name, + text, erstellt: n, zurueckgenommen: false, antwort: null, anhang: null, + }, [], "neu"); +} + /** Schreibt „Verpasster Anruf" in das Gespraech. * * Als ganz normale Nachricht des Anrufers: So steht sie an der @@ -341,6 +384,14 @@ anrufRouter.post("/workspace/api/anruf/:raum/start", gleicheHerkunft, laufend.set(raumId, { seit: Date.now(), video: mitVideo, + /* WER ANGERUFEN HAT -- eigens gemerkt (18.09.2026). + + `wer` ist die Runde der GERADE Anwesenden; sie aendert sich, + und am Ende ist sie leer. Fuer die Zeile im Chat („Anruf · + 3:42") braucht es aber den, der begonnen hat -- so wie bei + jedem Telefon. Aus einer Liste, die sich leert, laesst sich + das hinterher nicht mehr ablesen. */ + anrufer: { id: req.person.id, name: req.person.name }, wer: new Map([[req.person.id, { name: req.person.name, seit: Date.now() }]]), }); @@ -380,7 +431,14 @@ anrufRouter.post("/workspace/api/anruf/:raum/dabei", gleicheHerkunft, (req, res) if (a.wer.size >= GRUPPE_MAX) { return res.status(409).json({ fehler: `Es telefonieren schon ${GRUPPE_MAX}.` }); } - a.wer.set(req.person.id, { name: req.person.name, seit: Date.now() }); + /* WANN DAS GESPRAECH BEGINNT -- nicht, wann angerufen wurde. + + Die Dauer, die spaeter im Chat steht, soll die Zeit sein, in der + wirklich geredet wurde. Zaehlte man ab dem Klingeln, staende dort + bei jedem Anruf eine halbe Minute zu viel: die Zeit, in der das + Telefon nur laeutete. */ + if (!a.gespraechSeit && a.wer.size >= 1) a.gespraechSeit = Date.now(); + a.wer.set(req.person.id, { name: req.person.name, seit: Date.now() }); chatEreignis(raumId, { raum_id: raumId, art: "dabei", person: { id: req.person.id, name: req.person.name }, @@ -408,9 +466,21 @@ anrufRouter.post("/workspace/api/anruf/:raum/ende", gleicheHerkunft, (req, res) const a = laufend.get(raumId); if (a) { const war = a.wer.get(req.person.id); + const warGespraech = a.wer.size >= 2 || !!a.gespraechSeit; a.wer.delete(req.person.id); const dauer = war ? Math.round((Date.now() - war.seit) / 1000) : 0; - if (!a.wer.size) laufend.delete(raumId); + if (!a.wer.size) { + laufend.delete(raumId); + /* DER LETZTE GEHT -- also ist das Gespraech vorbei. Jetzt + gehoert eine Zeile in den Chat, wie bei jedem Telefon. + Eigenes try: Ein Fehler beim Schreiben darf das Auflegen + nicht scheitern lassen. */ + if (warGespraech) { + try { anrufVermerken(raumId, a); } catch (fe) { + console.error("[anruf] vermerken:", fe?.message); + } + } + } chatEreignis(raumId, { raum_id: raumId, art: a.wer.size ? "weg" : "ende", person: { id: req.person.id, name: req.person.name },