"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const express_1 = require("express"); const client_1 = require("@prisma/client"); const auth_js_1 = require("../middleware/auth.js"); const router = (0, express_1.Router)(); const prisma = new client_1.PrismaClient(); // Setup-Endpunkt: Erstellt die developer:access Permission und fügt sie der Admin-Rolle hinzu // Dieser Endpunkt erfordert keine Authentifizierung, da er nur einmalig zum Setup verwendet wird router.post('/setup', async (req, res) => { try { // Create or get the developer:access permission const developerPerm = await prisma.permission.upsert({ where: { resource_action: { resource: 'developer', action: 'access' } }, update: {}, create: { resource: 'developer', action: 'access' }, }); // Get the Admin role const adminRole = await prisma.role.findUnique({ where: { name: 'Admin' }, include: { permissions: true }, }); if (!adminRole) { res.status(404).json({ success: false, error: 'Admin-Rolle nicht gefunden' }); return; } // Check if Admin already has this permission const hasPermission = adminRole.permissions.some((rp) => rp.permissionId === developerPerm.id); if (!hasPermission) { await prisma.rolePermission.create({ data: { roleId: adminRole.id, permissionId: developerPerm.id, }, }); res.json({ success: true, message: 'developer:access Permission wurde zur Admin-Rolle hinzugefügt. Bitte neu einloggen!' }); } else { res.json({ success: true, message: 'Admin-Rolle hat bereits die developer:access Permission' }); } } catch (error) { console.error('Setup error:', error); res.status(500).json({ success: false, error: 'Fehler beim Setup' }); } }); // Tabellen-Metadaten mit Beziehungen const tableMetadata = { User: { model: 'user', primaryKey: 'id', readonlyFields: ['id', 'createdAt', 'updatedAt', 'password'], requiredFields: ['email', 'firstName', 'lastName'], relations: [ { field: 'customer', targetTable: 'Customer', type: 'one' }, { field: 'roles', targetTable: 'UserRole', type: 'many' }, ], foreignKeys: [{ field: 'customerId', targetTable: 'Customer' }], }, Role: { model: 'role', primaryKey: 'id', readonlyFields: ['id', 'createdAt', 'updatedAt'], requiredFields: ['name'], relations: [ { field: 'permissions', targetTable: 'RolePermission', type: 'many' }, { field: 'users', targetTable: 'UserRole', type: 'many' }, ], foreignKeys: [], }, Permission: { model: 'permission', primaryKey: 'id', readonlyFields: ['id'], requiredFields: ['resource', 'action'], relations: [{ field: 'roles', targetTable: 'RolePermission', type: 'many' }], foreignKeys: [], }, RolePermission: { model: 'rolePermission', primaryKey: 'roleId,permissionId', readonlyFields: [], requiredFields: ['roleId', 'permissionId'], relations: [], foreignKeys: [ { field: 'roleId', targetTable: 'Role' }, { field: 'permissionId', targetTable: 'Permission' }, ], }, UserRole: { model: 'userRole', primaryKey: 'userId,roleId', readonlyFields: [], requiredFields: ['userId', 'roleId'], relations: [], foreignKeys: [ { field: 'userId', targetTable: 'User' }, { field: 'roleId', targetTable: 'Role' }, ], }, Customer: { model: 'customer', primaryKey: 'id', readonlyFields: ['id', 'createdAt', 'updatedAt', 'customerNumber'], requiredFields: ['firstName', 'lastName'], relations: [ { field: 'user', targetTable: 'User', type: 'one' }, { field: 'addresses', targetTable: 'Address', type: 'many' }, { field: 'bankCards', targetTable: 'BankCard', type: 'many' }, { field: 'identityDocuments', targetTable: 'IdentityDocument', type: 'many' }, { field: 'meters', targetTable: 'Meter', type: 'many' }, { field: 'contracts', targetTable: 'Contract', type: 'many' }, ], foreignKeys: [], }, Address: { model: 'address', primaryKey: 'id', readonlyFields: ['id', 'createdAt', 'updatedAt'], requiredFields: ['customerId', 'street', 'houseNumber', 'postalCode', 'city'], relations: [ { field: 'customer', targetTable: 'Customer', type: 'one' }, { field: 'contracts', targetTable: 'Contract', type: 'many' }, ], foreignKeys: [{ field: 'customerId', targetTable: 'Customer' }], }, BankCard: { model: 'bankCard', primaryKey: 'id', readonlyFields: ['id', 'createdAt', 'updatedAt'], requiredFields: ['customerId', 'accountHolder', 'iban'], relations: [ { field: 'customer', targetTable: 'Customer', type: 'one' }, { field: 'contracts', targetTable: 'Contract', type: 'many' }, ], foreignKeys: [{ field: 'customerId', targetTable: 'Customer' }], }, IdentityDocument: { model: 'identityDocument', primaryKey: 'id', readonlyFields: ['id', 'createdAt', 'updatedAt'], requiredFields: ['customerId', 'documentNumber'], relations: [ { field: 'customer', targetTable: 'Customer', type: 'one' }, { field: 'contracts', targetTable: 'Contract', type: 'many' }, ], foreignKeys: [{ field: 'customerId', targetTable: 'Customer' }], }, Meter: { model: 'meter', primaryKey: 'id', readonlyFields: ['id', 'createdAt', 'updatedAt'], requiredFields: ['customerId', 'meterNumber', 'type'], relations: [ { field: 'customer', targetTable: 'Customer', type: 'one' }, { field: 'readings', targetTable: 'MeterReading', type: 'many' }, { field: 'energyDetails', targetTable: 'EnergyContractDetails', type: 'many' }, ], foreignKeys: [{ field: 'customerId', targetTable: 'Customer' }], }, MeterReading: { model: 'meterReading', primaryKey: 'id', readonlyFields: ['id', 'createdAt'], requiredFields: ['meterId', 'readingDate', 'value'], relations: [{ field: 'meter', targetTable: 'Meter', type: 'one' }], foreignKeys: [{ field: 'meterId', targetTable: 'Meter' }], }, SalesPlatform: { model: 'salesPlatform', primaryKey: 'id', readonlyFields: ['id', 'createdAt', 'updatedAt'], requiredFields: ['name'], relations: [{ field: 'contracts', targetTable: 'Contract', type: 'many' }], foreignKeys: [], }, Contract: { model: 'contract', primaryKey: 'id', readonlyFields: ['id', 'createdAt', 'updatedAt', 'contractNumber'], requiredFields: ['customerId', 'type'], relations: [ { field: 'customer', targetTable: 'Customer', type: 'one' }, { field: 'address', targetTable: 'Address', type: 'one' }, { field: 'bankCard', targetTable: 'BankCard', type: 'one' }, { field: 'identityDocument', targetTable: 'IdentityDocument', type: 'one' }, { field: 'salesPlatform', targetTable: 'SalesPlatform', type: 'one' }, { field: 'previousContract', targetTable: 'Contract', type: 'one' }, { field: 'followUpContract', targetTable: 'Contract', type: 'one' }, { field: 'energyDetails', targetTable: 'EnergyContractDetails', type: 'one' }, { field: 'internetDetails', targetTable: 'InternetContractDetails', type: 'one' }, { field: 'mobileDetails', targetTable: 'MobileContractDetails', type: 'one' }, { field: 'tvDetails', targetTable: 'TvContractDetails', type: 'one' }, { field: 'carInsuranceDetails', targetTable: 'CarInsuranceDetails', type: 'one' }, ], foreignKeys: [ { field: 'customerId', targetTable: 'Customer' }, { field: 'addressId', targetTable: 'Address' }, { field: 'bankCardId', targetTable: 'BankCard' }, { field: 'identityDocumentId', targetTable: 'IdentityDocument' }, { field: 'salesPlatformId', targetTable: 'SalesPlatform' }, { field: 'previousContractId', targetTable: 'Contract' }, ], }, EnergyContractDetails: { model: 'energyContractDetails', primaryKey: 'id', readonlyFields: ['id'], requiredFields: ['contractId'], relations: [ { field: 'contract', targetTable: 'Contract', type: 'one' }, { field: 'meter', targetTable: 'Meter', type: 'one' }, ], foreignKeys: [ { field: 'contractId', targetTable: 'Contract' }, { field: 'meterId', targetTable: 'Meter' }, ], }, InternetContractDetails: { model: 'internetContractDetails', primaryKey: 'id', readonlyFields: ['id'], requiredFields: ['contractId'], relations: [ { field: 'contract', targetTable: 'Contract', type: 'one' }, { field: 'phoneNumbers', targetTable: 'PhoneNumber', type: 'many' }, ], foreignKeys: [{ field: 'contractId', targetTable: 'Contract' }], }, PhoneNumber: { model: 'phoneNumber', primaryKey: 'id', readonlyFields: ['id'], requiredFields: ['internetContractDetailsId', 'phoneNumber'], relations: [{ field: 'internetDetails', targetTable: 'InternetContractDetails', type: 'one' }], foreignKeys: [{ field: 'internetContractDetailsId', targetTable: 'InternetContractDetails' }], }, MobileContractDetails: { model: 'mobileContractDetails', primaryKey: 'id', readonlyFields: ['id'], requiredFields: ['contractId'], relations: [{ field: 'contract', targetTable: 'Contract', type: 'one' }], foreignKeys: [{ field: 'contractId', targetTable: 'Contract' }], }, TvContractDetails: { model: 'tvContractDetails', primaryKey: 'id', readonlyFields: ['id'], requiredFields: ['contractId'], relations: [{ field: 'contract', targetTable: 'Contract', type: 'one' }], foreignKeys: [{ field: 'contractId', targetTable: 'Contract' }], }, CarInsuranceDetails: { model: 'carInsuranceDetails', primaryKey: 'id', readonlyFields: ['id'], requiredFields: ['contractId'], relations: [{ field: 'contract', targetTable: 'Contract', type: 'one' }], foreignKeys: [{ field: 'contractId', targetTable: 'Contract' }], }, }; // Schema-Informationen abrufen router.get('/schema', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('developer:access'), async (req, res) => { try { const tables = Object.entries(tableMetadata).map(([name, meta]) => ({ name, ...meta, })); res.json({ success: true, data: tables }); } catch (error) { console.error('Schema error:', error); res.status(500).json({ success: false, error: 'Fehler beim Laden des Schemas' }); } }); // Tabellen-Daten abrufen router.get('/table/:tableName', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('developer:access'), async (req, res) => { try { const { tableName } = req.params; const { page = '1', limit = '50' } = req.query; const meta = tableMetadata[tableName]; if (!meta) { res.status(404).json({ success: false, error: 'Tabelle nicht gefunden' }); return; } const skip = (parseInt(page) - 1) * parseInt(limit); const take = parseInt(limit); const model = prisma[meta.model]; const [data, total] = await Promise.all([ model.findMany({ skip, take, orderBy: meta.primaryKey.includes(',') ? undefined : { [meta.primaryKey.split(',')[0]]: 'desc' }, }), model.count(), ]); res.json({ success: true, data, meta: { ...meta, tableName, }, pagination: { page: parseInt(page), limit: parseInt(limit), total, totalPages: Math.ceil(total / parseInt(limit)), }, }); } catch (error) { console.error('Table data error:', error); res.status(500).json({ success: false, error: 'Fehler beim Laden der Daten' }); } }); // Einzelne Zeile aktualisieren router.put('/table/:tableName/:id', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('developer:access'), async (req, res) => { try { const { tableName, id } = req.params; const updates = req.body; const meta = tableMetadata[tableName]; if (!meta) { res.status(404).json({ success: false, error: 'Tabelle nicht gefunden' }); return; } // Readonly-Felder aus Updates entfernen const filteredUpdates = {}; for (const [key, value] of Object.entries(updates)) { if (!meta.readonlyFields.includes(key)) { filteredUpdates[key] = value; } } // Prüfen ob required-Felder nicht auf null/leer gesetzt werden for (const field of meta.requiredFields) { if (field in filteredUpdates && (filteredUpdates[field] === null || filteredUpdates[field] === '')) { res.status(400).json({ success: false, error: `Feld '${field}' ist erforderlich` }); return; } } const model = prisma[meta.model]; // Composite Primary Key Handling let where; if (meta.primaryKey.includes(',')) { const keys = meta.primaryKey.split(','); const idParts = id.split('-'); where = {}; keys.forEach((key, idx) => { where[key] = parseInt(idParts[idx]); }); } else { where = { [meta.primaryKey]: parseInt(id) }; } const updated = await model.update({ where, data: filteredUpdates, }); res.json({ success: true, data: updated }); } catch (error) { console.error('Update error:', error); if (error.code === 'P2003') { res.status(400).json({ success: false, error: 'Fremdschlüssel-Verletzung: Referenzierter Datensatz existiert nicht' }); } else if (error.code === 'P2002') { res.status(400).json({ success: false, error: 'Unique-Constraint-Verletzung: Wert existiert bereits' }); } else { res.status(500).json({ success: false, error: 'Fehler beim Aktualisieren' }); } } }); // Zeile löschen (nur wenn keine abhängigen Daten) router.delete('/table/:tableName/:id', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('developer:access'), async (req, res) => { try { const { tableName, id } = req.params; const meta = tableMetadata[tableName]; if (!meta) { res.status(404).json({ success: false, error: 'Tabelle nicht gefunden' }); return; } const model = prisma[meta.model]; // Composite Primary Key Handling let where; if (meta.primaryKey.includes(',')) { const keys = meta.primaryKey.split(','); const idParts = id.split('-'); where = {}; keys.forEach((key, idx) => { where[key] = parseInt(idParts[idx]); }); } else { where = { [meta.primaryKey]: parseInt(id) }; } // Prüfen ob abhängige Daten existieren (nur "many"-Relations) const record = await model.findUnique({ where, include: meta.relations .filter((r) => r.type === 'many') .reduce((acc, r) => ({ ...acc, [r.field]: { take: 1 } }), {}), }); if (!record) { res.status(404).json({ success: false, error: 'Datensatz nicht gefunden' }); return; } // Prüfen auf abhängige Daten for (const rel of meta.relations.filter((r) => r.type === 'many')) { if (record[rel.field] && record[rel.field].length > 0) { res.status(400).json({ success: false, error: `Kann nicht gelöscht werden: Es existieren abhängige Daten in '${rel.targetTable}'`, }); return; } } await model.delete({ where }); res.json({ success: true }); } catch (error) { console.error('Delete error:', error); if (error.code === 'P2003') { res.status(400).json({ success: false, error: 'Kann nicht gelöscht werden: Fremdschlüssel-Abhängigkeit' }); } else { res.status(500).json({ success: false, error: 'Fehler beim Löschen' }); } } }); // Referenzierte Daten für Dropdowns abrufen router.get('/reference/:tableName', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('developer:access'), async (req, res) => { try { const { tableName } = req.params; const { search = '', limit = '50' } = req.query; const meta = tableMetadata[tableName]; if (!meta) { res.status(404).json({ success: false, error: 'Tabelle nicht gefunden' }); return; } const model = prisma[meta.model]; const data = await model.findMany({ take: parseInt(limit), }); res.json({ success: true, data }); } catch (error) { console.error('Reference error:', error); res.status(500).json({ success: false, error: 'Fehler beim Laden der Referenzdaten' }); } }); exports.default = router; //# sourceMappingURL=developer.routes.js.map