Terminplaner: Empfaenger-Kappe ueber Betriebe (G01, Freitext in G04/G06)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Sonnet 5.5 committed 2026-10-04 10:03:39 +00:00
1 parent c35711caad
commit 4d96565240
5 files changed
+257 -18

No files matched your search

+71 -8
View File
@@ -11,6 +11,7 @@ import {
darfHaltung,
darfWiderrufsversuch,
darfG01,
darfEmpfaenger,
ipSchluessel,
resetTermineLimitsForTests,
} from '../server/services/termine/limits.js'
@@ -159,13 +160,75 @@ test('darfWiderrufsversuch: 10 je IP und Stunde', () => {
assert.equal(darfWiderrufsversuch('203.0.113.7', plus(STUNDE)), true)
})
test('darfG01: 5 je Adresse und Funktion und Tag; die Zaehler der Arten stoeren sich nicht', () => {
assert.deepEqual(Array.from({ length: 7 }, () => darfG01('f1', 'max@example.com', T0)), [true, true, true, true, true, false, false])
assert.equal(darfG01('f2', 'max@example.com', T0), true, 'andere Funktion')
test('darfG01: 3 je Adresse und Stunde ueber alle Funktionen; die Zaehler der Arten stoeren sich nicht', () => {
assert.deepEqual(Array.from({ length: 7 }, () => darfG01('f1', 'max@example.com', T0)), [true, true, true, false, false, false, false])
assert.equal(darfG01('f2', 'max@example.com', T0), false, 'die Kappe gilt ueber Betriebe (Funktionen) hinweg')
assert.equal(darfG01('f1', 'anna@example.com', T0), true, 'andere Adresse')
assert.equal(darfG01('f1', 'max@example.com', plus(TAG - 1)), false)
assert.equal(darfG01('f1', 'max@example.com', plus(TAG)), true, 'am naechsten Tag wieder')
assert.equal(darfG08('f1', 'max@example.com', T0), true, 'G08 zaehlt getrennt von G01')
assert.equal(darfG01('f1', 'max@example.com', plus(STUNDE - 1)), false, 'bis zur letzten Millisekunde der Stunde')
assert.deepEqual(
Array.from({ length: 4 }, () => darfG01('f2', 'max@example.com', plus(61 * MINUTE))),
[true, true, true, false],
'nach 61 Minuten wieder drei',
)
assert.deepEqual(
Array.from({ length: 4 }, () => darfG08('f1', 'max@example.com', T0)),
[true, true, true, false],
'G08 zaehlt getrennt von G01 und hat ihre eigene Grenze von drei je Tag',
)
})
test('darfG01: je Adresse hoechstens 10 Empfaenger-Mails pro Tag (3 + 3 + 3 + 1 ueber vier Stunden), die 11. nicht', () => {
// je Funktion gelten weiter hoechstens 5 G01 pro Tag; darum verteilen sich die zehn auf vier Funktionen
const adresse = 'tag@example.com'
const stunde = (n, funktion, anzahl) => Array.from({ length: anzahl }, () => darfG01(funktion, adresse, plus(n * 61 * MINUTE)))
assert.deepEqual(stunde(0, 'f1', 3), [true, true, true])
assert.deepEqual(stunde(1, 'f2', 3), [true, true, true])
assert.deepEqual(stunde(2, 'f3', 3), [true, true, true])
assert.deepEqual(stunde(3, 'f4', 2), [true, false], 'die zehnte geht, die elfte nicht (der Stundenzaehler hat dann erst eine)')
assert.equal(darfG01('f5', adresse, plus(5 * 61 * MINUTE)), false, 'auch in einer neuen Stunde und mit unberuehrter Funktion')
assert.equal(darfG01('f5', 'andere@example.com', plus(5 * 61 * MINUTE)), true, 'andere Adresse')
assert.equal(darfG01('f5', adresse, plus(TAG)), true, 'am naechsten Tag wieder')
})
test('darfG01: je Funktion hoechstens 5 pro Adresse und Tag (die Regel der Funktion bleibt neben der Kappe ueber Betriebe)', () => {
const adresse = 'funktion@example.com'
assert.deepEqual(Array.from({ length: 3 }, () => darfG01('f1', adresse, T0)), [true, true, true])
assert.deepEqual(Array.from({ length: 3 }, () => darfG01('f1', adresse, plus(61 * MINUTE))), [true, true, false], 'die sechste an dieselbe Funktion nicht')
assert.equal(darfG01('f2', adresse, plus(61 * MINUTE)), true, 'eine andere Funktion schon (noch ein Platz in der Stunde)')
assert.equal(darfG01('f1', adresse, plus(TAG)), true, 'am naechsten Tag wieder')
})
test('darfG01: alles oder nichts - eine abgelehnte Anfrage erhoeht keinen Zaehler, auch nicht den der Funktion', () => {
const adresse = 'nichts@example.com'
assert.deepEqual(Array.from({ length: 3 }, () => darfG01('f1', adresse, T0)), [true, true, true])
// von der Stundenkappe abgelehnt: der Zaehler der Funktion (3 von 5) bleibt bei 3
for (let i = 0; i < 6; i += 1) assert.equal(darfG01('f1', adresse, T0), false)
assert.deepEqual(Array.from({ length: 3 }, () => darfG01('f1', adresse, plus(61 * MINUTE))), [true, true, false], 'danach noch genau 2 von 5 frei')
// von der Funktionsregel abgelehnt: Stunden- und Tageszaehler (2 und 5) bleiben unveraendert
for (let i = 0; i < 4; i += 1) assert.equal(darfG01('f1', adresse, plus(62 * MINUTE)), false)
assert.deepEqual(Array.from({ length: 2 }, () => darfG01('f2', adresse, plus(62 * MINUTE))), [true, false], 'in der Stunde ist genau 1 von 3 frei')
// bisher 6 am Tag gezaehlt (3 + 2 + 1): drei weitere und dann eine ergeben genau die zehn des Tages
assert.deepEqual(Array.from({ length: 3 }, () => darfG01('f3', adresse, plus(123 * MINUTE))), [true, true, true])
assert.deepEqual(Array.from({ length: 2 }, () => darfG01('f4', adresse, plus(184 * MINUTE))), [true, false], 'die zehnte war die letzte des Tages')
})
test('darfEmpfaenger: teilt Stunden- und Tageszaehler mit darfG01, ohne die Regel der Funktion', () => {
const adresse = 'frei@example.com'
assert.deepEqual(
[darfEmpfaenger(adresse, T0), darfEmpfaenger(adresse, T0), darfG01('f1', adresse, T0), darfG01('f1', adresse, T0)],
[true, true, true, false],
'zwei Freitext-Mails + zwei G01: die vierte Mail an dieselbe Adresse in der Stunde nicht',
)
assert.equal(darfEmpfaenger(adresse, T0), false)
assert.equal(darfEmpfaenger('anna@example.com', T0), true, 'andere Adresse')
assert.equal(darfEmpfaenger(adresse, plus(61 * MINUTE)), true, 'nach 61 Minuten wieder')
// die G01-Regel der Funktion (5 je Tag) zaehlt nur bei darfG01: fuenf G01 sind verbraucht, ein Freitext geht trotzdem
const andere = 'regel@example.com'
for (let i = 0; i < 3; i += 1) assert.equal(darfG01('f1', andere, plus(i * 61 * MINUTE)), true)
for (let i = 0; i < 2; i += 1) assert.equal(darfG01('f1', andere, plus(3 * 61 * MINUTE)), true)
assert.equal(darfG01('f1', andere, plus(3 * 61 * MINUTE)), false, 'sechste G01 an dieselbe Funktion')
assert.equal(darfEmpfaenger(andere, plus(3 * 61 * MINUTE)), true, 'der Freitext kennt die Regel der Funktion nicht')
})
// ---------------------------------------------------------------- Speicher: IP-Zaehler getrennt, Abgelaufene zuerst
@@ -174,8 +237,8 @@ test('darfG01: 5 je Adresse und Funktion und Tag; die Zaehler der Arten stoeren
const ipNr = (i) => `10.${(i >> 16) & 255}.${(i >> 8) & 255}.${i & 255}`
test('Speicher: 10 000 und mehr verschiedene IPs verdraengen keinen laufenden Zaehler je Adresse, Funktion oder siteKey', () => {
// G01 einer Adresse ausgeschoepft, eine Haltungsgrenze angebrochen
for (let i = 0; i < 5; i += 1) assert.equal(darfG01('f1', 'opfer@example.com', T0), true)
// G01 einer Adresse ausgeschoepft (3 je Stunde), eine Haltungsgrenze angebrochen
for (let i = 0; i < 3; i += 1) assert.equal(darfG01('f1', 'opfer@example.com', T0), true)
assert.equal(darfG01('f1', 'opfer@example.com', T0), false)
for (let i = 0; i < 25; i += 1) assert.equal(darfHaltung('abcdefghijklmnop', T0), true)
assert.equal(darfG08('f1', 'opfer@example.com', T0), true)