opencrm/backend/dist/routes/upload.routes.js

575 lines
25 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const express_1 = require("express");
const multer_1 = __importDefault(require("multer"));
const path_1 = __importDefault(require("path"));
const fs_1 = __importDefault(require("fs"));
const prisma_js_1 = __importDefault(require("../lib/prisma.js"));
const auth_js_1 = require("../middleware/auth.js");
const audit_service_js_1 = require("../services/audit.service.js");
const router = (0, express_1.Router)();
// Uploads-Verzeichnis erstellen falls nicht vorhanden
const uploadsDir = path_1.default.join(process.cwd(), 'uploads');
if (!fs_1.default.existsSync(uploadsDir)) {
fs_1.default.mkdirSync(uploadsDir, { recursive: true });
}
// Multer-Konfiguration
const storage = multer_1.default.diskStorage({
destination: (req, file, cb) => {
const subDir = req.uploadSubDir || 'misc';
const targetDir = path_1.default.join(uploadsDir, subDir);
if (!fs_1.default.existsSync(targetDir)) {
fs_1.default.mkdirSync(targetDir, { recursive: true });
}
cb(null, targetDir);
},
filename: (req, file, cb) => {
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1e9);
const ext = path_1.default.extname(file.originalname);
cb(null, `${uniqueSuffix}${ext}`);
},
});
const fileFilter = (req, file, cb) => {
// Nur PDFs und Bilder erlauben
const allowedTypes = ['application/pdf', 'image/jpeg', 'image/png', 'image/jpg'];
if (allowedTypes.includes(file.mimetype)) {
cb(null, true);
}
else {
cb(new Error('Nur PDF, JPG und PNG Dateien sind erlaubt'));
}
};
const upload = (0, multer_1.default)({
storage,
fileFilter,
limits: {
fileSize: 10 * 1024 * 1024, // 10MB max
},
});
// Middleware um Subdirectory zu setzen
function setUploadDir(subDir) {
return (req, res, next) => {
req.uploadSubDir = subDir;
next();
};
}
// Upload für Bankkarten-Dokumente
router.post('/bank-cards/:id', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('customers:update'), setUploadDir('bank-cards'), upload.single('document'), async (req, res) => {
try {
if (!req.file) {
res.status(400).json({ success: false, error: 'Keine Datei hochgeladen' });
return;
}
const bankCardId = parseInt(req.params.id);
const relativePath = `/uploads/bank-cards/${req.file.filename}`;
// Bankkarte in der DB aktualisieren
await prisma_js_1.default.bankCard.update({
where: { id: bankCardId },
data: { documentPath: relativePath },
});
res.json({
success: true,
data: {
path: relativePath,
filename: req.file.filename,
originalName: req.file.originalname,
size: req.file.size,
},
});
}
catch (error) {
console.error('Upload error:', error);
res.status(500).json({ success: false, error: 'Upload fehlgeschlagen' });
}
});
// Upload für Ausweis-Dokumente
router.post('/documents/:id', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('customers:update'), setUploadDir('documents'), upload.single('document'), async (req, res) => {
try {
if (!req.file) {
res.status(400).json({ success: false, error: 'Keine Datei hochgeladen' });
return;
}
const documentId = parseInt(req.params.id);
const relativePath = `/uploads/documents/${req.file.filename}`;
// Ausweis in der DB aktualisieren
await prisma_js_1.default.identityDocument.update({
where: { id: documentId },
data: { documentPath: relativePath },
});
res.json({
success: true,
data: {
path: relativePath,
filename: req.file.filename,
originalName: req.file.originalname,
size: req.file.size,
},
});
}
catch (error) {
console.error('Upload error:', error);
res.status(500).json({ success: false, error: 'Upload fehlgeschlagen' });
}
});
// Löschen von Bankkarten-Dokumenten
router.delete('/bank-cards/:id', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('customers:update'), async (req, res) => {
try {
const bankCardId = parseInt(req.params.id);
// Bankkarte aus DB holen um Dateipfad zu bekommen
const bankCard = await prisma_js_1.default.bankCard.findUnique({
where: { id: bankCardId },
});
if (!bankCard) {
res.status(404).json({ success: false, error: 'Bankkarte nicht gefunden' });
return;
}
if (!bankCard.documentPath) {
res.status(400).json({ success: false, error: 'Kein Dokument vorhanden' });
return;
}
// Datei von Festplatte löschen
const filePath = path_1.default.join(process.cwd(), bankCard.documentPath);
if (fs_1.default.existsSync(filePath)) {
fs_1.default.unlinkSync(filePath);
}
// documentPath in DB auf null setzen
await prisma_js_1.default.bankCard.update({
where: { id: bankCardId },
data: { documentPath: null },
});
res.json({ success: true });
}
catch (error) {
console.error('Delete error:', error);
res.status(500).json({ success: false, error: 'Löschen fehlgeschlagen' });
}
});
// Löschen von Ausweis-Dokumenten
router.delete('/documents/:id', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('customers:update'), async (req, res) => {
try {
const documentId = parseInt(req.params.id);
// Ausweis aus DB holen um Dateipfad zu bekommen
const document = await prisma_js_1.default.identityDocument.findUnique({
where: { id: documentId },
});
if (!document) {
res.status(404).json({ success: false, error: 'Ausweis nicht gefunden' });
return;
}
if (!document.documentPath) {
res.status(400).json({ success: false, error: 'Kein Dokument vorhanden' });
return;
}
// Datei von Festplatte löschen
const filePath = path_1.default.join(process.cwd(), document.documentPath);
if (fs_1.default.existsSync(filePath)) {
fs_1.default.unlinkSync(filePath);
}
// documentPath in DB auf null setzen
await prisma_js_1.default.identityDocument.update({
where: { id: documentId },
data: { documentPath: null },
});
res.json({ success: true });
}
catch (error) {
console.error('Delete error:', error);
res.status(500).json({ success: false, error: 'Löschen fehlgeschlagen' });
}
});
// ==================== FIRMEN-DOKUMENTE ====================
// Upload für Gewerbeanmeldung
router.post('/customers/:id/business-registration', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('customers:update'), setUploadDir('business-registrations'), upload.single('document'), async (req, res) => {
try {
if (!req.file) {
res.status(400).json({ success: false, error: 'Keine Datei hochgeladen' });
return;
}
const customerId = parseInt(req.params.id);
const relativePath = `/uploads/business-registrations/${req.file.filename}`;
// Alte Datei löschen falls vorhanden
const customer = await prisma_js_1.default.customer.findUnique({ where: { id: customerId } });
if (customer?.businessRegistrationPath) {
const oldPath = path_1.default.join(process.cwd(), customer.businessRegistrationPath);
if (fs_1.default.existsSync(oldPath)) {
fs_1.default.unlinkSync(oldPath);
}
}
// Kunde in der DB aktualisieren
await prisma_js_1.default.customer.update({
where: { id: customerId },
data: { businessRegistrationPath: relativePath },
});
res.json({
success: true,
data: {
path: relativePath,
filename: req.file.filename,
originalName: req.file.originalname,
size: req.file.size,
},
});
}
catch (error) {
console.error('Upload error:', error);
res.status(500).json({ success: false, error: 'Upload fehlgeschlagen' });
}
});
// Upload für Handelsregisterauszug
router.post('/customers/:id/commercial-register', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('customers:update'), setUploadDir('commercial-registers'), upload.single('document'), async (req, res) => {
try {
if (!req.file) {
res.status(400).json({ success: false, error: 'Keine Datei hochgeladen' });
return;
}
const customerId = parseInt(req.params.id);
const relativePath = `/uploads/commercial-registers/${req.file.filename}`;
// Alte Datei löschen falls vorhanden
const customer = await prisma_js_1.default.customer.findUnique({ where: { id: customerId } });
if (customer?.commercialRegisterPath) {
const oldPath = path_1.default.join(process.cwd(), customer.commercialRegisterPath);
if (fs_1.default.existsSync(oldPath)) {
fs_1.default.unlinkSync(oldPath);
}
}
// Kunde in der DB aktualisieren
await prisma_js_1.default.customer.update({
where: { id: customerId },
data: { commercialRegisterPath: relativePath },
});
res.json({
success: true,
data: {
path: relativePath,
filename: req.file.filename,
originalName: req.file.originalname,
size: req.file.size,
},
});
}
catch (error) {
console.error('Upload error:', error);
res.status(500).json({ success: false, error: 'Upload fehlgeschlagen' });
}
});
// Löschen der Gewerbeanmeldung
router.delete('/customers/:id/business-registration', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('customers:update'), async (req, res) => {
try {
const customerId = parseInt(req.params.id);
const customer = await prisma_js_1.default.customer.findUnique({ where: { id: customerId } });
if (!customer) {
res.status(404).json({ success: false, error: 'Kunde nicht gefunden' });
return;
}
if (!customer.businessRegistrationPath) {
res.status(400).json({ success: false, error: 'Kein Dokument vorhanden' });
return;
}
// Datei löschen
const filePath = path_1.default.join(process.cwd(), customer.businessRegistrationPath);
if (fs_1.default.existsSync(filePath)) {
fs_1.default.unlinkSync(filePath);
}
// Pfad in DB auf null setzen
await prisma_js_1.default.customer.update({
where: { id: customerId },
data: { businessRegistrationPath: null },
});
res.json({ success: true });
}
catch (error) {
console.error('Delete error:', error);
res.status(500).json({ success: false, error: 'Löschen fehlgeschlagen' });
}
});
// Löschen des Handelsregisterauszugs
router.delete('/customers/:id/commercial-register', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('customers:update'), async (req, res) => {
try {
const customerId = parseInt(req.params.id);
const customer = await prisma_js_1.default.customer.findUnique({ where: { id: customerId } });
if (!customer) {
res.status(404).json({ success: false, error: 'Kunde nicht gefunden' });
return;
}
if (!customer.commercialRegisterPath) {
res.status(400).json({ success: false, error: 'Kein Dokument vorhanden' });
return;
}
// Datei löschen
const filePath = path_1.default.join(process.cwd(), customer.commercialRegisterPath);
if (fs_1.default.existsSync(filePath)) {
fs_1.default.unlinkSync(filePath);
}
// Pfad in DB auf null setzen
await prisma_js_1.default.customer.update({
where: { id: customerId },
data: { commercialRegisterPath: null },
});
res.json({ success: true });
}
catch (error) {
console.error('Delete error:', error);
res.status(500).json({ success: false, error: 'Löschen fehlgeschlagen' });
}
});
// ==================== DATENSCHUTZERKLÄRUNG (für alle Kunden) ====================
// Upload für Datenschutzerklärung
router.post('/customers/:id/privacy-policy', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('customers:update'), setUploadDir('privacy-policies'), upload.single('document'), async (req, res) => {
try {
if (!req.file) {
res.status(400).json({ success: false, error: 'Keine Datei hochgeladen' });
return;
}
const customerId = parseInt(req.params.id);
const relativePath = `/uploads/privacy-policies/${req.file.filename}`;
// Alte Datei löschen falls vorhanden
const customer = await prisma_js_1.default.customer.findUnique({ where: { id: customerId } });
if (customer?.privacyPolicyPath) {
const oldPath = path_1.default.join(process.cwd(), customer.privacyPolicyPath);
if (fs_1.default.existsSync(oldPath)) {
fs_1.default.unlinkSync(oldPath);
}
}
// Kunde in der DB aktualisieren
await prisma_js_1.default.customer.update({
where: { id: customerId },
data: { privacyPolicyPath: relativePath },
});
// Alle Consents auf GRANTED setzen (PDF = vollständige Einwilligung)
const consentTypes = ['DATA_PROCESSING', 'MARKETING_EMAIL', 'MARKETING_PHONE', 'DATA_SHARING_PARTNER'];
for (const consentType of consentTypes) {
await prisma_js_1.default.customerConsent.upsert({
where: { customerId_consentType: { customerId, consentType } },
update: { status: 'GRANTED', grantedAt: new Date(), source: 'papier' },
create: { customerId, consentType, status: 'GRANTED', grantedAt: new Date(), source: 'papier', createdBy: req.user?.email || 'admin' },
});
}
// Audit
const cust = await prisma_js_1.default.customer.findUnique({ where: { id: customerId }, select: { firstName: true, lastName: true } });
await (0, audit_service_js_1.logChange)({
req, action: 'CREATE', resourceType: 'CustomerConsent',
label: `Datenschutzerklärung-PDF hochgeladen für ${cust?.firstName} ${cust?.lastName} alle Einwilligungen erteilt`,
details: { aktion: 'PDF hochgeladen', einwilligungen: 'alle erteilt', quelle: 'papier' },
customerId,
});
res.json({
success: true,
data: {
path: relativePath,
filename: req.file.filename,
originalName: req.file.originalname,
size: req.file.size,
},
});
}
catch (error) {
console.error('Upload error:', error);
res.status(500).json({ success: false, error: 'Upload fehlgeschlagen' });
}
});
// Löschen der Datenschutzerklärung
router.delete('/customers/:id/privacy-policy', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('customers:update'), async (req, res) => {
try {
const customerId = parseInt(req.params.id);
const customer = await prisma_js_1.default.customer.findUnique({ where: { id: customerId } });
if (!customer) {
res.status(404).json({ success: false, error: 'Kunde nicht gefunden' });
return;
}
if (!customer.privacyPolicyPath) {
res.status(400).json({ success: false, error: 'Kein Dokument vorhanden' });
return;
}
// Datei löschen
const filePath = path_1.default.join(process.cwd(), customer.privacyPolicyPath);
if (fs_1.default.existsSync(filePath)) {
fs_1.default.unlinkSync(filePath);
}
// Pfad in DB auf null setzen
await prisma_js_1.default.customer.update({
where: { id: customerId },
data: { privacyPolicyPath: null },
});
// Nur Consents widerrufen die per Papier erteilt wurden
await prisma_js_1.default.customerConsent.updateMany({
where: { customerId, status: 'GRANTED', source: 'papier' },
data: { status: 'WITHDRAWN', withdrawnAt: new Date() },
});
// Audit
const cust = await prisma_js_1.default.customer.findUnique({ where: { id: customerId }, select: { firstName: true, lastName: true } });
await (0, audit_service_js_1.logChange)({
req, action: 'DELETE', resourceType: 'CustomerConsent',
label: `Datenschutzerklärung-PDF gelöscht für ${cust?.firstName} ${cust?.lastName} Papier-Einwilligungen widerrufen`,
details: { aktion: 'PDF gelöscht', einwilligungen: 'papier-basierte widerrufen' },
customerId,
});
res.json({ success: true });
}
catch (error) {
console.error('Delete error:', error);
res.status(500).json({ success: false, error: 'Löschen fehlgeschlagen' });
}
});
// ==================== VERTRAGS-DOKUMENTE ====================
// Generische Funktion für Vertrags-Dokument Upload
async function handleContractDocumentUpload(req, res, fieldName, subDir) {
try {
if (!req.file) {
res.status(400).json({ success: false, error: 'Keine Datei hochgeladen' });
return;
}
const contractId = parseInt(req.params.id);
const relativePath = `/uploads/${subDir}/${req.file.filename}`;
// Alte Datei löschen falls vorhanden
const contract = await prisma_js_1.default.contract.findUnique({ where: { id: contractId } });
if (!contract) {
res.status(404).json({ success: false, error: 'Vertrag nicht gefunden' });
return;
}
const oldPath = contract[fieldName];
if (oldPath) {
const fullPath = path_1.default.join(process.cwd(), oldPath);
if (fs_1.default.existsSync(fullPath)) {
fs_1.default.unlinkSync(fullPath);
}
}
// Vertrag in der DB aktualisieren
await prisma_js_1.default.contract.update({
where: { id: contractId },
data: { [fieldName]: relativePath },
});
res.json({
success: true,
data: {
path: relativePath,
filename: req.file.filename,
originalName: req.file.originalname,
size: req.file.size,
},
});
}
catch (error) {
console.error('Upload error:', error);
res.status(500).json({ success: false, error: 'Upload fehlgeschlagen' });
}
}
// Generische Funktion für Vertrags-Dokument Löschen
async function handleContractDocumentDelete(req, res, fieldName) {
try {
const contractId = parseInt(req.params.id);
const contract = await prisma_js_1.default.contract.findUnique({ where: { id: contractId } });
if (!contract) {
res.status(404).json({ success: false, error: 'Vertrag nicht gefunden' });
return;
}
const documentPath = contract[fieldName];
if (!documentPath) {
res.status(400).json({ success: false, error: 'Kein Dokument vorhanden' });
return;
}
// Datei löschen
const filePath = path_1.default.join(process.cwd(), documentPath);
if (fs_1.default.existsSync(filePath)) {
fs_1.default.unlinkSync(filePath);
}
// Pfad in DB auf null setzen
await prisma_js_1.default.contract.update({
where: { id: contractId },
data: { [fieldName]: null },
});
res.json({ success: true });
}
catch (error) {
console.error('Delete error:', error);
res.status(500).json({ success: false, error: 'Löschen fehlgeschlagen' });
}
}
// Kündigungsschreiben
router.post('/contracts/:id/cancellation-letter', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('contracts:update'), setUploadDir('cancellation-letters'), upload.single('document'), (req, res) => handleContractDocumentUpload(req, res, 'cancellationLetterPath', 'cancellation-letters'));
router.delete('/contracts/:id/cancellation-letter', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('contracts:update'), (req, res) => handleContractDocumentDelete(req, res, 'cancellationLetterPath'));
// Kündigungsbestätigung
router.post('/contracts/:id/cancellation-confirmation', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('contracts:update'), setUploadDir('cancellation-confirmations'), upload.single('document'), (req, res) => handleContractDocumentUpload(req, res, 'cancellationConfirmationPath', 'cancellation-confirmations'));
router.delete('/contracts/:id/cancellation-confirmation', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('contracts:update'), (req, res) => handleContractDocumentDelete(req, res, 'cancellationConfirmationPath'));
// Kündigungsschreiben Optionen
router.post('/contracts/:id/cancellation-letter-options', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('contracts:update'), setUploadDir('cancellation-letters-options'), upload.single('document'), (req, res) => handleContractDocumentUpload(req, res, 'cancellationLetterOptionsPath', 'cancellation-letters-options'));
router.delete('/contracts/:id/cancellation-letter-options', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('contracts:update'), (req, res) => handleContractDocumentDelete(req, res, 'cancellationLetterOptionsPath'));
// Kündigungsbestätigung Optionen
router.post('/contracts/:id/cancellation-confirmation-options', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('contracts:update'), setUploadDir('cancellation-confirmations-options'), upload.single('document'), (req, res) => handleContractDocumentUpload(req, res, 'cancellationConfirmationOptionsPath', 'cancellation-confirmations-options'));
router.delete('/contracts/:id/cancellation-confirmation-options', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('contracts:update'), (req, res) => handleContractDocumentDelete(req, res, 'cancellationConfirmationOptionsPath'));
// ==================== RECHNUNGS-DOKUMENTE ====================
// Upload für Rechnungs-Dokument
router.post('/invoices/:id', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('contracts:update'), setUploadDir('invoices'), upload.single('document'), async (req, res) => {
try {
if (!req.file) {
res.status(400).json({ success: false, error: 'Keine Datei hochgeladen' });
return;
}
const invoiceId = parseInt(req.params.id);
const relativePath = `/uploads/invoices/${req.file.filename}`;
// Alte Datei löschen falls vorhanden
const invoice = await prisma_js_1.default.invoice.findUnique({ where: { id: invoiceId } });
if (!invoice) {
res.status(404).json({ success: false, error: 'Rechnung nicht gefunden' });
return;
}
if (invoice.documentPath) {
const oldPath = path_1.default.join(process.cwd(), invoice.documentPath);
if (fs_1.default.existsSync(oldPath)) {
fs_1.default.unlinkSync(oldPath);
}
}
// Invoice in der DB aktualisieren
await prisma_js_1.default.invoice.update({
where: { id: invoiceId },
data: { documentPath: relativePath },
});
res.json({
success: true,
data: {
path: relativePath,
filename: req.file.filename,
originalName: req.file.originalname,
size: req.file.size,
},
});
}
catch (error) {
console.error('Invoice upload error:', error);
res.status(500).json({ success: false, error: 'Upload fehlgeschlagen' });
}
});
// Löschen von Rechnungs-Dokument
router.delete('/invoices/:id', auth_js_1.authenticate, (0, auth_js_1.requirePermission)('contracts:update'), async (req, res) => {
try {
const invoiceId = parseInt(req.params.id);
const invoice = await prisma_js_1.default.invoice.findUnique({ where: { id: invoiceId } });
if (!invoice) {
res.status(404).json({ success: false, error: 'Rechnung nicht gefunden' });
return;
}
if (!invoice.documentPath) {
res.status(400).json({ success: false, error: 'Kein Dokument vorhanden' });
return;
}
// Datei löschen
const filePath = path_1.default.join(process.cwd(), invoice.documentPath);
if (fs_1.default.existsSync(filePath)) {
fs_1.default.unlinkSync(filePath);
}
// documentPath in DB auf null setzen
await prisma_js_1.default.invoice.update({
where: { id: invoiceId },
data: { documentPath: null },
});
res.json({ success: true });
}
catch (error) {
console.error('Invoice delete error:', error);
res.status(500).json({ success: false, error: 'Löschen fehlgeschlagen' });
}
});
exports.default = router;
//# sourceMappingURL=upload.routes.js.map