Files
Webklar-Kundenbereich/server/routes/unterkunftSeite.js
T
2026-10-07 14:32:34 +00:00

56 lines
2.7 KiB
JavaScript

import { Router } from 'express'
import { config } from '../config.js'
import { listDocuments, Query } from '../services/appwriteAdmin.js'
import { baueIcs } from '../services/unterkunft/ical.js'
import { ladeFuerProjekt } from '../services/unterkunft/kontext.js'
import { unterkunftFuerKunde, unterkunftModus } from '../services/unterkunft/schalter.js'
import { listeAnfragenNachStatus, listeSperren } from '../services/unterkunft/speicher.js'
/**
* Oeffentliche Standalone-Seiten des Buchungskalenders: /unterkunft/:siteKey und /unterkunft/:siteKey/buchung/:id
* (Vorbild: shopSeite.js). Geruest (Task 5): Task 7 und Strang 3 fuellen die Seiten.
* Davor steht der iCal-Export /unterkunft/ical/<token>.ics (Task 9): die Adresse ist das Geheimnis (Token, 43 Zeichen).
*/
const DATEI_RE = /^[A-Za-z0-9_-]{20,64}\.ics$/
const nicht = (res) => res.status(404).type('text/plain').set('Cache-Control', 'no-store').send('Not found')
async function exportEreignisse(unterkunft, jetzt) {
const out = []
for (const s of await listeSperren(unterkunft.$id)) {
const quelle = String(s.quelle ?? 'manuell')
if (quelle.startsWith('ical') || !s.von || !s.bis) continue // nie zurueckspielen, was importiert wurde
out.push({ uid: `${s.$id}@project.webklar.com`, von: s.von, bis: s.bis })
}
for (const a of await listeAnfragenNachStatus(unterkunft.$id, ['gebucht', 'bezahlt', 'freigegeben'])) {
if (a.status === 'freigegeben' && !(Date.parse(a.fristAt) > jetzt)) continue
if (!a.von || !a.bis) continue
out.push({ uid: `${a.$id}@project.webklar.com`, von: a.von, bis: a.bis })
}
return out.sort((x, y) => (x.von < y.von ? -1 : x.von > y.von ? 1 : x.uid < y.uid ? -1 : 1))
}
export function unterkunftSeiteRouter() {
const router = Router()
router.get('/unterkunft/ical/:datei', async (req, res, next) => {
try {
if (unterkunftModus() === 'off' || !DATEI_RE.test(req.params.datei)) return nicht(res)
const token = req.params.datei.slice(0, -4)
const [u] = await listDocuments(config.collections.ukUnterkuenfte, [Query.equal('icalExportToken', token), Query.limit(1)])
if (!u || u.icalExportToken !== token) return nicht(res)
const ctx = await ladeFuerProjekt(u.customerId, u.projectId)
if (!ctx || ctx.featureId !== u.featureId || ctx.state !== 'active' || !unterkunftFuerKunde(ctx.besitzerEmail)) return nicht(res)
const jetzt = new Date()
const text = baueIcs({ name: u.name, ereignisse: await exportEreignisse(u, jetzt.getTime()), jetzt })
res.set({ 'Content-Type': 'text/calendar; charset=utf-8', 'Cache-Control': 'no-store', 'X-Content-Type-Options': 'nosniff' }).send(text)
} catch (err) {
next(err)
}
})
return router
}
export default unterkunftSeiteRouter