81 lines
2.8 KiB
JavaScript
81 lines
2.8 KiB
JavaScript
import { randomBytes } from 'node:crypto'
|
|
import { clearPortalSession, setPortalSession } from '../middleware/session.js'
|
|
import { logViewAction } from './customerViewLog.js'
|
|
import {
|
|
PREVIEW_COOKIE_NAME,
|
|
clearPreviewSession,
|
|
createPreviewSessionToken,
|
|
previewSessionCookieOptions,
|
|
} from './previewSession.js'
|
|
|
|
/**
|
|
* Kundenansicht aus dem Ticketsystem (Spec 2026-10-01, Abschnitt 3): ein Mitarbeiter oeffnet per Einmal-Link das
|
|
* Portal eines Kunden. Die Sitzung traegt eine zufaellige Kennung (viewId) gegen Verwechslung zweier Tabs und
|
|
* endet nach 2 Stunden. Sitzungen ohne viewId stammen aus "Als Kunde ansehen" im alten Admin-Panel.
|
|
*/
|
|
export const KUNDENANSICHT_TTL_MS = 2 * 60 * 60 * 1000
|
|
|
|
export const isKundenansicht = (session) => Boolean(session?.viewAs && session.viewId)
|
|
|
|
export const isExpired = (session, now = Date.now()) => now >= Number(session?.viewExpiresAt || 0)
|
|
|
|
/** Portal-Sitzung und Preview-Zugang fuer genau diesen Kunden setzen; liefert die Sitzung. */
|
|
export async function startKundenansicht(res, { staff, customer, now = Date.now() }) {
|
|
const session = {
|
|
role: 'admin',
|
|
viewAs: true,
|
|
viewId: randomBytes(16).toString('hex'),
|
|
viewExpiresAt: now + KUNDENANSICHT_TTL_MS,
|
|
isAdmin: Boolean(staff.isAdmin),
|
|
appwriteUserId: staff.appwriteUserId,
|
|
adminName: staff.name || 'Mitarbeiter',
|
|
adminEmail: staff.email || '',
|
|
customerId: customer.$id,
|
|
name: customer.name || '',
|
|
email: customer.email || '',
|
|
}
|
|
setPortalSession(res, session, { maxAgeMs: KUNDENANSICHT_TTL_MS })
|
|
await setKundenansichtPreview(res, session, KUNDENANSICHT_TTL_MS / 1000)
|
|
return session
|
|
}
|
|
|
|
/** Preview-Cookie wie beim Kunden selbst (nur seine Projekte), hoechstens bis zum Ende der Kundenansicht. */
|
|
export async function setKundenansichtPreview(res, session, maxAgeSec) {
|
|
const token = await createPreviewSessionToken(
|
|
{
|
|
userId: session.appwriteUserId,
|
|
customerId: session.customerId,
|
|
email: session.email || '',
|
|
name: session.name || '',
|
|
role: 'customer',
|
|
labels: [],
|
|
authSource: 'kundenansicht',
|
|
},
|
|
{ maxAgeSec }
|
|
)
|
|
return res.cookie(PREVIEW_COOKIE_NAME, token, previewSessionCookieOptions({ maxAgeSec }))
|
|
}
|
|
|
|
export function endKundenansicht(res) {
|
|
clearPortalSession(res)
|
|
clearPreviewSession(res)
|
|
}
|
|
|
|
// "beendet"/"abgelaufen" je Ansicht nur einmal protokollieren (parallele Anfragen eines Tabs)
|
|
const LOGGED_TTL_MS = 3 * 60 * 60 * 1000
|
|
const logged = new Map()
|
|
|
|
export async function logOnce(session, action) {
|
|
const now = Date.now()
|
|
for (const [key, at] of logged) if (now - at > LOGGED_TTL_MS) logged.delete(key)
|
|
const key = `${session.viewId}:${action}`
|
|
if (logged.has(key)) return
|
|
logged.set(key, now)
|
|
await logViewAction({
|
|
customerId: session.customerId,
|
|
staffUserId: session.appwriteUserId,
|
|
staffName: session.adminName,
|
|
action,
|
|
})
|
|
}
|