- Login: Appwrite-User mit Label 'admin' (Ticketsystem-Mitarbeiter) bekommen eine Admin-Session und landen auf /admin.html - Admin-Dashboard: Statistik-Uebersicht, Projektsuche ueber alle Projekte (inkl. Preview-/Gitea-Links, Vorschau ohne Kunden-Login), Kundenliste mit Portal-Status, letztem Login und Projektanzahl - Kundennummer (code) direkt im Admin-Bereich pflegbar - 'Als Kunde ansehen': Admin sieht das Portal exakt wie der Kunde (Banner mit Rueckweg zur Admin-Uebersicht) - Kunden-Dashboard: neue Bereiche 'Meine Rechnungen' (InvoiceNinja inkl. Link ins Rechnungsportal) und 'Was wurde gemacht' (Tickets + Worksheets aus dem Ticketsystem, ohne interne Akquise-Tickets); Kundennummer im Header - Admin-API /api/portal-admin/* (Session-basiert), Kunden-API /api/invoices und /api/activity - appwriteClient: uebrig gebliebene Debug-Instrumentierung entfernt Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
64 lines
1.6 KiB
JavaScript
64 lines
1.6 KiB
JavaScript
import cookieParser from 'cookie-parser'
|
|
import { config } from '../config.js'
|
|
|
|
const SESSION_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1000
|
|
|
|
export function sessionMiddleware() {
|
|
return cookieParser(config.sessionSecret)
|
|
}
|
|
|
|
export function setPortalSession(res, data) {
|
|
res.cookie(config.cookieName, JSON.stringify(data), {
|
|
httpOnly: true,
|
|
secure: process.env.NODE_ENV === 'production',
|
|
sameSite: 'lax',
|
|
maxAge: SESSION_MAX_AGE_MS,
|
|
signed: true,
|
|
})
|
|
}
|
|
|
|
export function clearPortalSession(res) {
|
|
res.clearCookie(config.cookieName, {
|
|
httpOnly: true,
|
|
secure: process.env.NODE_ENV === 'production',
|
|
sameSite: 'lax',
|
|
signed: true,
|
|
})
|
|
}
|
|
|
|
export function parsePortalSession(req) {
|
|
const raw = req.signedCookies?.[config.cookieName]
|
|
if (!raw) return null
|
|
try {
|
|
return JSON.parse(raw)
|
|
} catch {
|
|
return null
|
|
}
|
|
}
|
|
|
|
export function requireSession(req, res, next) {
|
|
const session = parsePortalSession(req)
|
|
if (!session) {
|
|
return res.status(401).json({ error: 'Nicht angemeldet' })
|
|
}
|
|
if (!session.customerId || !session.appwriteUserId) {
|
|
return res.status(401).json({ error: 'Ungültige Session' })
|
|
}
|
|
req.session = session
|
|
next()
|
|
}
|
|
|
|
/** Admin-Session: Ticketsystem-Mitarbeiter (Appwrite-Label "admin") im Portal. */
|
|
export function requireAdminSession(req, res, next) {
|
|
const session = parsePortalSession(req)
|
|
if (!session?.appwriteUserId || session.role !== 'admin') {
|
|
return res.status(401).json({ error: 'Admin-Anmeldung erforderlich' })
|
|
}
|
|
req.session = session
|
|
next()
|
|
}
|
|
|
|
export function getSessionCustomerId(req) {
|
|
return req.session?.customerId
|
|
}
|