From b22e1923cd85e1d546488734b44cc03bc45aff77 Mon Sep 17 00:00:00 2001 From: "Torsten Schulz (local)" Date: Tue, 9 Jun 2026 12:05:10 +0200 Subject: [PATCH] =?UTF-8?q?Fehldende=20messages=20hinzugef=C3=BCgt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/services/falukantService.js | 61 ++++++++++++------- .../components/falukant/MessagesDialog.vue | 24 ++++++-- 2 files changed, 59 insertions(+), 26 deletions(-) diff --git a/backend/services/falukantService.js b/backend/services/falukantService.js index fbbdec4..44e9454 100644 --- a/backend/services/falukantService.js +++ b/backend/services/falukantService.js @@ -8961,9 +8961,45 @@ function serializeNotificationForClient(row) { const j = typeof row.toJSON === 'function' ? row.toJSON() : { ...row }; const dv = row.dataValues || {}; if (dv.region_name != null && j.region_name == null) j.region_name = dv.region_name; + j.tr = normalizeNotificationTrForClient(j.tr); return j; } +function parseNotificationTrPayload(tr) { + if (tr && typeof tr === 'object') return tr; + if (typeof tr !== 'string') return null; + const trimmed = tr.trim(); + if (!trimmed) return null; + + const jsonStart = trimmed.indexOf('{'); + if (jsonStart < 0) return null; + + try { + const parsed = JSON.parse(trimmed.slice(jsonStart)); + return parsed && typeof parsed === 'object' ? parsed : null; + } catch { + return null; + } +} + +function isMissingNotificationTrKey(value) { + if (value == null) return true; + const text = String(value).trim(); + return !text || text === 'falukant.notifications.' || text === 'notifications.'; +} + +function normalizeNotificationTrForClient(tr) { + const parsed = parseNotificationTrPayload(tr); + if (!parsed) return tr; + + const normalized = { ...parsed }; + if (isMissingNotificationTrKey(normalized.tr) && normalized.event) { + normalized.tr = String(normalized.event); + } + + return JSON.stringify(normalized); +} + // Helper: parse notifications for character references and attach characterName async function enrichNotificationsWithCharacterNames(notifications) { if (!Array.isArray(notifications) || notifications.length === 0) return; @@ -8999,18 +9035,8 @@ async function enrichNotificationsWithCharacterNames(notifications) { // First pass: collect all referenced character ids and region ids from notifications for (const n of notifications) { - let parsed = null; - try { - if (typeof n.tr === 'string' && n.tr.trim().startsWith('{')) { - parsed = JSON.parse(n.tr); - collectIds(parsed); - } else if (n.tr && typeof n.tr === 'object') { - parsed = n.tr; - collectIds(parsed); - } - } catch (err) { - parsed = null; - } + const parsed = parseNotificationTrPayload(n.tr); + if (parsed) collectIds(parsed); if (parsed?.region_id != null) { regionIds.add(Number(parsed.region_id)); } @@ -9093,16 +9119,7 @@ async function enrichNotificationsWithCharacterNames(notifications) { // Attach resolved name to notifications (set character_name; characterName is a getter that reads from it) for (const n of notifications) { - let parsed = null; - try { - if (typeof n.tr === 'string' && n.tr.trim().startsWith('{')) { - parsed = JSON.parse(n.tr); - } else if (n.tr && typeof n.tr === 'object') { - parsed = n.tr; - } - } catch (err) { - parsed = null; - } + const parsed = parseNotificationTrPayload(n.tr); let foundId = null; if (parsed?.director_character_id != null) { diff --git a/frontend/src/components/falukant/MessagesDialog.vue b/frontend/src/components/falukant/MessagesDialog.vue index 42d97ff..7f1c814 100644 --- a/frontend/src/components/falukant/MessagesDialog.vue +++ b/frontend/src/components/falukant/MessagesDialog.vue @@ -143,11 +143,15 @@ export default { } if (typeof raw === 'string') { const trimmed = raw.trim(); - if (trimmed.startsWith('{') && trimmed.endsWith('}')) { + const jsonStart = trimmed.indexOf('{'); + if (jsonStart >= 0 && trimmed.endsWith('}')) { try { - const parsed = JSON.parse(trimmed); + const parsed = JSON.parse(trimmed.slice(jsonStart)); if (parsed && typeof parsed === 'object') { merged = { ...merged, ...parsed }; + if (!parsed.tr && parsed.event && /^falukant\.notifications\.\s*\{/.test(trimmed)) { + merged.tr = parsed.event; + } } } catch { /* Rohstring bleibt in merged.tr */ @@ -175,17 +179,29 @@ export default { let raw = payload.tr || ''; let key = raw; let params = {}; + const isMissingNotificationKey = (value) => { + if (value == null) return true; + const text = String(value).trim(); + return !text || text === 'falukant.notifications.' || text === 'notifications.'; + }; // Fallback: Manche Daemon-Events liefern event_id/event_type, aber kein tr. - if ((!raw || !String(raw).trim()) && payload?.event_id) { + if (isMissingNotificationKey(raw) && payload?.event_id) { raw = payload.event_type === 'random_event' ? `random_event.${payload.event_id}` : String(payload.event_id); key = raw; } + // Fallback: direkte Daemon-Events wie director_death liefern den Typ + // im Feld event, waehrend tr historisch leer oder nur der Namespace sein kann. + if (isMissingNotificationKey(raw) && payload?.event) { + raw = String(payload.event); + key = raw; + } + // Fallback: use payload.type if present (e.g. storage_damage) - if ((!raw || !String(raw).trim()) && payload?.type) { + if (isMissingNotificationKey(raw) && payload?.type) { raw = String(payload.type); key = raw; }