Kundenansicht: Einmal-Link aus dem Ticketsystem, Sitzung und Preview-Zugang fuer 2 Stunden, Protokoll
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
fdf594706d
commit
1cd776a2ee
10 files changed
+277
-7
No files matched your search
@@ -28,6 +28,9 @@ import {
|
||||
} from '../services/previewSession.js'
|
||||
import { isPreviewProjectReady } from '../services/previewReadiness.js'
|
||||
import { consumeStaffPreviewToken } from '../services/staffPreviewTokens.js'
|
||||
import { getPortalAccessStatus } from '../services/portalAccessStatus.js'
|
||||
import { startKundenansicht } from '../services/kundenansicht.js'
|
||||
import { logViewAction } from '../services/customerViewLog.js'
|
||||
import { resolveStaffAccount } from '../services/staffAccount.js'
|
||||
import { MFA_COOKIE, MFA_TTL_MS, resendStaffMfa, startStaffMfa, verifyStaffMfa } from '../services/staffMfa.js'
|
||||
|
||||
@@ -343,6 +346,28 @@ router.get('/staff-switch', async (req, res) => {
|
||||
return res.redirect('/admin.html')
|
||||
})
|
||||
|
||||
// Kundenansicht aus dem Ticketsystem (POST /api/team/customers/:id/kundenansicht): Einmal-Link -> Portal des Kunden
|
||||
router.get('/kundenansicht', async (req, res) => {
|
||||
const gone = (text) => res.status(410).type('text/plain; charset=utf-8').send(text)
|
||||
const tokenData = consumeStaffPreviewToken(String(req.query.token || ''), 'kundenansicht')
|
||||
if (!tokenData) return gone('Der Link ist abgelaufen. Bitte die Kundenansicht im Ticketsystem erneut öffnen.')
|
||||
try {
|
||||
const { customer, hasAccess } = await getPortalAccessStatus(tokenData.customerId)
|
||||
if (!customer || !hasAccess) return gone('Kein Portal-Zugang. Bitte die Kundenansicht im Ticketsystem erneut öffnen.')
|
||||
const session = await startKundenansicht(res, { staff: tokenData.staff, customer })
|
||||
await logViewAction({
|
||||
customerId: customer.$id,
|
||||
staffUserId: session.appwriteUserId,
|
||||
staffName: session.adminName,
|
||||
action: 'geoeffnet',
|
||||
})
|
||||
return res.redirect('/dashboard.html')
|
||||
} catch (err) {
|
||||
console.error('[kundenansicht] Öffnen fehlgeschlagen:', err.message)
|
||||
return res.status(500).type('text/plain; charset=utf-8').send('Die Kundenansicht konnte nicht geöffnet werden.')
|
||||
}
|
||||
})
|
||||
|
||||
// Selbstheilung: Portal-Session lebt oft laenger als das preview_session-Cookie
|
||||
// (bzw. das Cookie fehlt nach WebView-/Browser-Datenverlust). Ohne gueltiges
|
||||
// Preview-Cookie laufen die *.project.webklar.com-Hosts in eine 302-Schleife.
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import { Router } from 'express'
|
||||
import { config } from '../../config.js'
|
||||
import { getPortalAccessStatus } from '../../services/portalAccessStatus.js'
|
||||
import { createStaffPreviewToken } from '../../services/staffPreviewTokens.js'
|
||||
|
||||
// Kunden im Team-Eingang (/api/team/customers), requireStaffJwt sitzt in routes/team/index.js
|
||||
const router = Router()
|
||||
|
||||
// Kundenansicht oeffnen: Einmal-Link (60 s), den das Ticketsystem in einem neuen Tab aufruft
|
||||
router.post('/:id/kundenansicht', async (req, res) => {
|
||||
try {
|
||||
const { customer, hasAccess } = await getPortalAccessStatus(req.params.id)
|
||||
if (!customer) return res.status(404).json({ error: 'Kunde nicht gefunden' })
|
||||
if (!hasAccess) return res.status(409).json({ code: 'no_portal_access', error: 'Kein Portal-Zugang' })
|
||||
const token = createStaffPreviewToken({ purpose: 'kundenansicht', customerId: customer.$id, staff: req.staff })
|
||||
return res.json({ openUrl: `${config.publicBaseUrl}/api/auth/kundenansicht?token=${encodeURIComponent(token)}` })
|
||||
} catch (err) {
|
||||
return res.status(500).json({ error: err.message || 'Kundenansicht konnte nicht geöffnet werden' })
|
||||
}
|
||||
})
|
||||
|
||||
export default router
|
||||
@@ -1,8 +1,10 @@
|
||||
import { Router } from 'express'
|
||||
import { requireStaffJwt } from '../../middleware/staffJwt.js'
|
||||
import customersRoutes from './customers.js'
|
||||
|
||||
// Team-Eingang fuer das Ticketsystem: alle Mitarbeiter, Appwrite-JWT (Spec 2026-10-01 Admin-Panel ins Ticketsystem)
|
||||
const router = Router()
|
||||
router.use(requireStaffJwt)
|
||||
router.use('/customers', customersRoutes)
|
||||
|
||||
export default router
|
||||
Reference in new issue
Block a user