Terminplaner: Kunden-Schnittstelle – Nachbesserungen

- GET /zeiten?ohne=<Buchung>: Leistung, Dauer und Person der Buchung wie beim
  Verschieben (verschiebeZeiten exportiert), unbekannte/fremde/Sperre 404 (R42)
- Schreib-Begrenzung als gemeinsamer Baustein (writeLimiter.js) fuer News und
  Terminplaner statt kopierter Funktion (R43)
- Unlesbares Einstellungs-JSON: Kontext traegt die echte Version, Speichern
  ueberschreibt den Schaden statt dauerhaft 409
- U+FEFF als Escape statt als rohes Zeichen
- Tests: Mandantentrennung mit echtem zweitem Kunden, R42, Limiter, kaputtes JSON

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Sonnet 5.5 committed 2026-10-03 08:17:43 +00:00
1 parent e3e198fb1a
commit bb45d35ec7
8 files changed
+319 -65

No files matched your search

+21
View File
@@ -502,6 +502,27 @@ test('kontextPerFeature: active und disabled liefern ctx, auch ohne Einstellung
assert.equal(await kontextPerFeature(undefined), null)
})
test('unlesbares Einstellungs-JSON: der Kontext traegt die echte Version (einstellung null), Speichern mit ihr ueberschreibt den Schaden', async () => {
seedFeature()
seedProjekt()
aw.seed('termineConfig', { $id: FEATURE, customerId: KUNDE, projectId: PROJEKT, einstellung: '{kaputt', version: 3 })
const ctx = await kontextPerFeature(FEATURE)
assert.equal(ctx.einstellung, null, 'nichts Lesbares')
assert.equal(ctx.version, 3, 'aber die gespeicherte Version, nicht 0')
assert.equal(await ladeEinstellung(FEATURE), null, 'ladeEinstellung bleibt: unlesbar = nicht gespeichert')
assert.equal(await kontextPerSiteKey(SITE_KEY, T0), null, 'oeffentlich nicht buchbar')
// mit Version 0 (dem alten Wert des Kontexts) ging es nie; mit der echten gelingt es und die Funktion bekommt bisher = null
await assert.rejects(() => speichereEinstellung(feature(), einstellung(), { version: 0 }), (err) => err.status === 409)
let gesehen
const erg = await speichereEinstellung(feature(), async (bisher) => { gesehen = bisher; return einstellung() }, { version: ctx.version })
assert.equal(gesehen, null)
assert.equal(erg.version, 4)
const danach = await kontextPerFeature(FEATURE)
assert.equal(danach.version, 4)
assert.equal(danach.einstellung.betrieb.name, 'Salon Müller')
})
test('kontextPerFeature: Modus off => null ohne Anfrage; fehlendes Projekt => project null', async () => {
seedFeature()
await speichereEinstellung(feature(), einstellung(), { version: 0 })