import prisma from '../lib/prisma.js'; import bcrypt from 'bcryptjs'; import jwt from 'jsonwebtoken'; import { JwtPayload } from '../types/index.js'; import { encrypt, decrypt } from '../utils/encryption.js'; // Mitarbeiter-Login export async function login(email: string, password: string) { const user = await prisma.user.findUnique({ where: { email }, include: { roles: { include: { role: { include: { permissions: { include: { permission: true, }, }, }, }, }, }, }, }); if (!user || !user.isActive) { throw new Error('Ungültige Anmeldedaten'); } const isValid = await bcrypt.compare(password, user.password); if (!isValid) { throw new Error('Ungültige Anmeldedaten'); } // Collect all permissions from all roles const permissions = new Set(); for (const userRole of user.roles) { for (const rolePerm of userRole.role.permissions) { permissions.add( `${rolePerm.permission.resource}:${rolePerm.permission.action}` ); } } const payload: JwtPayload = { userId: user.id, email: user.email, permissions: Array.from(permissions), customerId: user.customerId ?? undefined, isCustomerPortal: false, }; const token = jwt.sign(payload, process.env.JWT_SECRET || 'fallback-secret', { expiresIn: (process.env.JWT_EXPIRES_IN || '7d') as jwt.SignOptions['expiresIn'], }); return { token, user: { id: user.id, email: user.email, firstName: user.firstName, lastName: user.lastName, permissions: Array.from(permissions), customerId: user.customerId, isCustomerPortal: false, }, }; } // Kundenportal-Login export async function customerLogin(email: string, password: string) { console.log('[CustomerLogin] Versuch mit E-Mail:', email); const customer = await prisma.customer.findUnique({ where: { portalEmail: email }, include: { // Kunden, die dieser Kunde vertreten kann representingFor: { where: { isActive: true }, include: { customer: { select: { id: true, customerNumber: true, firstName: true, lastName: true, companyName: true, type: true, }, }, }, }, }, }); console.log('[CustomerLogin] Kunde gefunden:', customer ? `ID ${customer.id}, portalEnabled: ${customer.portalEnabled}, hasPasswordHash: ${!!customer.portalPasswordHash}` : 'NEIN'); if (!customer || !customer.portalEnabled || !customer.portalPasswordHash) { console.log('[CustomerLogin] Abbruch: Kunde nicht gefunden oder Portal nicht aktiviert'); throw new Error('Ungültige Anmeldedaten'); } const isValid = await bcrypt.compare(password, customer.portalPasswordHash); console.log('[CustomerLogin] Passwort-Check:', isValid ? 'OK' : 'FALSCH'); if (!isValid) { throw new Error('Ungültige Anmeldedaten'); } // Letzte Anmeldung aktualisieren await prisma.customer.update({ where: { id: customer.id }, data: { portalLastLogin: new Date() }, }); // IDs der Kunden sammeln, die dieser Kunde vertreten kann const representedCustomerIds = customer.representingFor.map( (rep) => rep.customer.id ); // Kundenportal-Berechtigungen (eingeschränkt) const customerPermissions = [ 'contracts:read', // Eigene Verträge lesen 'customers:read', // Eigene Kundendaten lesen ]; const payload: JwtPayload = { email: customer.portalEmail!, permissions: customerPermissions, customerId: customer.id, isCustomerPortal: true, representedCustomerIds, }; const token = jwt.sign(payload, process.env.JWT_SECRET || 'fallback-secret', { expiresIn: (process.env.JWT_EXPIRES_IN || '7d') as jwt.SignOptions['expiresIn'], }); return { token, user: { id: customer.id, email: customer.portalEmail, firstName: customer.firstName, lastName: customer.lastName, permissions: customerPermissions, customerId: customer.id, isCustomerPortal: true, representedCustomers: customer.representingFor.map((rep) => ({ id: rep.customer.id, customerNumber: rep.customer.customerNumber, firstName: rep.customer.firstName, lastName: rep.customer.lastName, companyName: rep.customer.companyName, type: rep.customer.type, })), }, }; } // Kundenportal-Passwort setzen/ändern export async function setCustomerPortalPassword(customerId: number, password: string) { console.log('[SetPortalPassword] Setze Passwort für Kunde:', customerId); const hashedPassword = await bcrypt.hash(password, 10); const encryptedPassword = encrypt(password); console.log('[SetPortalPassword] Hash erstellt, Länge:', hashedPassword.length); await prisma.customer.update({ where: { id: customerId }, data: { portalPasswordHash: hashedPassword, portalPasswordEncrypted: encryptedPassword, }, }); console.log('[SetPortalPassword] Passwort gespeichert'); } // Kundenportal-Passwort im Klartext abrufen export async function getCustomerPortalPassword(customerId: number): Promise { const customer = await prisma.customer.findUnique({ where: { id: customerId }, select: { portalPasswordEncrypted: true }, }); if (!customer?.portalPasswordEncrypted) { return null; } try { return decrypt(customer.portalPasswordEncrypted); } catch (error) { console.error('Fehler beim Entschlüsseln des Passworts:', error); return null; } } export async function createUser(data: { email: string; password: string; firstName: string; lastName: string; roleIds: number[]; customerId?: number; }) { const hashedPassword = await bcrypt.hash(data.password, 10); const user = await prisma.user.create({ data: { email: data.email, password: hashedPassword, firstName: data.firstName, lastName: data.lastName, customerId: data.customerId, roles: { create: data.roleIds.map((roleId) => ({ roleId })), }, }, include: { roles: { include: { role: true, }, }, }, }); return { id: user.id, email: user.email, firstName: user.firstName, lastName: user.lastName, roles: user.roles.map((ur) => ur.role.name), }; } export async function getUserById(id: number) { const user = await prisma.user.findUnique({ where: { id }, include: { roles: { include: { role: { include: { permissions: { include: { permission: true, }, }, }, }, }, }, }, }); if (!user) return null; console.log('auth.getUserById - user roles:', user.roles.map(ur => ur.role.name)); const permissions = new Set(); for (const userRole of user.roles) { for (const rolePerm of userRole.role.permissions) { permissions.add( `${rolePerm.permission.resource}:${rolePerm.permission.action}` ); } } console.log('auth.getUserById - permissions:', Array.from(permissions)); return { id: user.id, email: user.email, firstName: user.firstName, lastName: user.lastName, isActive: user.isActive, customerId: user.customerId, whatsappNumber: user.whatsappNumber, telegramUsername: user.telegramUsername, signalNumber: user.signalNumber, roles: user.roles.map((ur) => ur.role.name), permissions: Array.from(permissions), isCustomerPortal: false, }; } // Kundenportal-Benutzer laden (für /me Endpoint) export async function getCustomerPortalUser(customerId: number) { const customer = await prisma.customer.findUnique({ where: { id: customerId }, include: { representingFor: { where: { isActive: true }, include: { customer: { select: { id: true, customerNumber: true, firstName: true, lastName: true, companyName: true, type: true, }, }, }, }, }, }); if (!customer || !customer.portalEnabled) return null; const customerPermissions = [ 'contracts:read', 'customers:read', ]; return { id: customer.id, email: customer.portalEmail, firstName: customer.firstName, lastName: customer.lastName, isActive: customer.portalEnabled, customerId: customer.id, permissions: customerPermissions, isCustomerPortal: true, representedCustomers: customer.representingFor.map((rep) => ({ id: rep.customer.id, customerNumber: rep.customer.customerNumber, firstName: rep.customer.firstName, lastName: rep.customer.lastName, companyName: rep.customer.companyName, type: rep.customer.type, })), }; }