import { Router } from 'express' import { config } from '../config.js' import { getCustomerByAppwriteUserId, getCustomerByEmail, getPortalAccessByCustomerId, updateDocument, } from '../services/appwriteAdmin.js' import { loginWithAppwrite, getLoginCooldownRemainingSec } from '../services/appwriteClient.js' import { clearPortalSession, setPortalSession, } from '../middleware/session.js' const router = Router() function sanitizeCustomer(customer) { return { id: customer.$id, code: customer.code || '', name: customer.name || '', companyName: customer.companyName || '', email: customer.email || '', phone: customer.phone || '', location: customer.location || '', customerStatus: customer.customerStatus || '', portalAccessEnabled: Boolean(customer.portalAccessEnabled), } } async function validatePortalAccess(appwriteUserId, email) { let customer = await getCustomerByAppwriteUserId(appwriteUserId) if (!customer && email) { customer = await getCustomerByEmail(email) } if (!customer) { const error = new Error( `Kein Kundenkonto für diesen Login gefunden. Im Ticketsystem customers.appwriteUserId auf "${appwriteUserId}" setzen (E-Mail: ${email}).` ) error.status = 403 throw error } if (!customer.portalAccessEnabled) { const error = new Error('Portalzugang ist nicht freigeschaltet.') error.status = 403 throw error } const portalAccess = await getPortalAccessByCustomerId(customer.$id) if (!portalAccess || !portalAccess.enabled) { const error = new Error('Portalzugang ist deaktiviert.') error.status = 403 throw error } const status = (customer.customerStatus || '').toLowerCase() if (!config.allowedCustomerStatuses.includes(status)) { const error = new Error('Kundenkonto ist nicht aktiv.') error.status = 403 throw error } return { customer, portalAccess } } router.get('/login-status', (_req, res) => { const retryAfterSeconds = getLoginCooldownRemainingSec() res.json({ blocked: retryAfterSeconds > 0, retryAfterSeconds, }) }) router.post('/login', async (req, res) => { const { email, password } = req.body || {} if (!email || !password) { return res.status(400).json({ error: 'E-Mail und Passwort erforderlich' }) } try { const user = await loginWithAppwrite(email.trim(), password) const { customer, portalAccess } = await validatePortalAccess(user.$id, email.trim()) setPortalSession(res, { customerId: customer.$id, appwriteUserId: user.$id, name: customer.name || user.name || '', email: customer.email || user.email || email, }) try { await updateDocument(config.collections.customerPortalAccess, portalAccess.$id, { lastLoginAt: new Date().toISOString(), }) } catch (err) { console.warn('[auth] lastLoginAt update failed:', err.message) } return res.json({ success: true, customer: sanitizeCustomer(customer) }) } catch (err) { const status = err.status || 500 if (status === 429) { return res.status(429).json({ error: err.message || 'Zu viele Anmeldeversuche. Bitte warte einige Minuten, bevor du es erneut versuchst.', retryAfterSeconds: getLoginCooldownRemainingSec(), }) } if (err?.message?.includes('not authorized')) { return res.status(500).json({ error: 'Server-Konfiguration: APPWRITE_API_KEY benötigt databases.read für woms-database (customers, customerPortalAccess).', }) } return res.status(status).json({ error: err.message || 'Anmeldung fehlgeschlagen' }) } }) router.post('/logout', (_req, res) => { clearPortalSession(res) res.json({ success: true }) }) router.get('/me', async (req, res) => { const raw = req.signedCookies?.[config.cookieName] if (!raw) { return res.json({ authenticated: false }) } try { const session = JSON.parse(raw) if (!session.customerId || !session.appwriteUserId) { return res.json({ authenticated: false }) } const customer = await getCustomerByAppwriteUserId(session.appwriteUserId) if (!customer) { clearPortalSession(res) return res.json({ authenticated: false }) } return res.json({ authenticated: true, customer: sanitizeCustomer(customer), }) } catch (err) { return res.status(500).json({ error: err.message || 'Fehler beim Laden' }) } }) export default router