Terminplaner: Zellen nur unter der Ressourcensperre freigeben, gemeinsame Hilfsfunktionen

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 e281db1b2b
commit 9ad8515d60
6 files changed
+284 -71

No files matched your search

+7 -11
View File
@@ -3,6 +3,7 @@ import { config } from '../../config.js'
import { Query, createDocument, getDocument, listAllDocuments, listDocuments, updateDocument } from '../appwriteAdmin.js'
import { istBelegend } from './slots.js'
import { buchungsNummer } from './token.js'
import { pruefeNow } from './util.js'
/**
* Buchungsspeicher des Terminplaners: nur Datenzugriff auf termineBookings (Spezifikation 2026-10-02-terminplaner-
@@ -33,11 +34,6 @@ const LOESCH_BEZUG = {
const iso = (wert) => new Date(wert).toISOString()
const kleinGetrimmt = (email) => (typeof email === 'string' ? email.trim().toLowerCase() : '')
function jetztMs(now, name) {
if (!(now instanceof Date) || Number.isNaN(now.getTime())) throw new TypeError(`${name}: now fehlt`)
return now.getTime()
}
/** Ohne die von Appwrite gelieferten $-Felder ($id, $createdAt, ...), die nie zurueckgeschrieben werden duerfen. */
const nurFelder = (daten) => Object.fromEntries(Object.entries(daten).filter(([key]) => !key.startsWith('$')))
@@ -97,7 +93,7 @@ export async function perHash(feld, hash) {
* zu Ende. Die Adresse zaehlt klein und getrimmt. => Buchungen (die Grenze maxOffeneJeEmail prueft der Aufrufer).
*/
export async function offeneFuerEmail(featureId, email, now) {
const nowMs = jetztMs(now, 'offeneFuerEmail')
const nowMs = pruefeNow(now, 'offeneFuerEmail')
const mail = kleinGetrimmt(email)
if (!mail) return []
const kandidaten = await listAllDocuments(col(), [
@@ -123,7 +119,7 @@ export async function perEmailUndNummer(featureId, email, nummer) {
* normalisiereEinstellung.
*/
export async function zaehleKuenftige(featureId, now) {
const nowMs = jetztMs(now, 'zaehleKuenftige')
const nowMs = pruefeNow(now, 'zaehleKuenftige')
const liste = await listAllDocuments(col(), [
Query.equal('featureId', featureId),
Query.equal('status', BELEGEND),
@@ -144,7 +140,7 @@ export async function zaehleKuenftige(featureId, now) {
/** Haltungen (alle Funktionen), die abgelaufen sind (heldUntil <= jetzt): der Minutenjob macht sie zu verfallen. */
export async function abgelaufeneHaltungen(now) {
jetztMs(now, 'abgelaufeneHaltungen')
pruefeNow(now, 'abgelaufeneHaltungen')
return listAllDocuments(col(), [Query.equal('status', 'gehalten'), Query.lessThanEqual('heldUntil', iso(now))])
}
@@ -153,7 +149,7 @@ export async function abgelaufeneHaltungen(now) {
* (jetzt + 1 h, jetzt + 48 h]. Den Vorlauf der Funktion (stundenVorher) und den Vertragsschluss prueft der Job.
*/
export async function erinnerungsKandidaten(now) {
const nowMs = jetztMs(now, 'erinnerungsKandidaten')
const nowMs = pruefeNow(now, 'erinnerungsKandidaten')
const liste = await listAllDocuments(col(), [
Query.equal('status', 'bestaetigt'),
Query.equal('erinnerung', true),
@@ -165,13 +161,13 @@ export async function erinnerungsKandidaten(now) {
/** Bestaetigte Buchungen (alle Funktionen, auch Sperren), deren Ende mehr als 1 h her ist: der Job macht sie erledigt. */
export async function zuErledigen(now) {
const nowMs = jetztMs(now, 'zuErledigen')
const nowMs = pruefeNow(now, 'zuErledigen')
return listAllDocuments(col(), [Query.equal('status', 'bestaetigt'), Query.lessThan('endsAt', iso(nowMs - STUNDE_MS))])
}
/** Anfragen (alle Funktionen), deren Beginn vorbei ist: der Job lehnt sie vom System aus ab. */
export async function vergangeneAnfragen(now) {
jetztMs(now, 'vergangeneAnfragen')
pruefeNow(now, 'vergangeneAnfragen')
return listAllDocuments(col(), [Query.equal('status', 'angefragt'), Query.lessThan('startsAt', iso(now))])
}