170 lines
6.2 KiB
TypeScript
170 lines
6.2 KiB
TypeScript
import { Request, Response } from 'express';
|
||
import * as consentPublicService from '../services/consent-public.service.js';
|
||
import { createAuditLog } from '../services/audit.service.js';
|
||
import { CONSENT_TYPE_LABELS } from '../services/consent.service.js';
|
||
import { ConsentType } from '@prisma/client';
|
||
import { sendEmail } from '../services/smtpService.js';
|
||
import { getSystemEmailCredentials } from '../services/emailProvider/emailProviderService.js';
|
||
|
||
/**
|
||
* Öffentliche Consent-Seite: Kundendaten + Datenschutztext + Status
|
||
*/
|
||
export async function getConsentPage(req: Request, res: Response) {
|
||
try {
|
||
const { hash } = req.params;
|
||
|
||
const result = await consentPublicService.getCustomerByConsentHash(hash);
|
||
if (!result) {
|
||
return res.status(404).json({ success: false, error: 'Ungültiger Link' });
|
||
}
|
||
|
||
const privacyPolicyHtml = await consentPublicService.getPrivacyPolicyHtml(result.customer.id);
|
||
|
||
// Consent-Status mit Labels
|
||
const consentsWithLabels = result.consents.map((c) => ({
|
||
consentType: c.consentType,
|
||
status: c.status,
|
||
label: CONSENT_TYPE_LABELS[c.consentType as ConsentType]?.label || c.consentType,
|
||
description: CONSENT_TYPE_LABELS[c.consentType as ConsentType]?.description || '',
|
||
grantedAt: c.grantedAt,
|
||
}));
|
||
|
||
res.json({
|
||
success: true,
|
||
data: {
|
||
customer: {
|
||
firstName: result.customer.firstName,
|
||
lastName: result.customer.lastName,
|
||
customerNumber: result.customer.customerNumber,
|
||
},
|
||
privacyPolicyHtml,
|
||
consents: consentsWithLabels,
|
||
allGranted: consentsWithLabels.every((c) => c.status === 'GRANTED'),
|
||
},
|
||
});
|
||
} catch (error) {
|
||
console.error('Fehler beim Laden der Consent-Seite:', error);
|
||
res.status(500).json({ success: false, error: 'Fehler beim Laden' });
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Alle 4 Einwilligungen erteilen (öffentlicher Link)
|
||
*/
|
||
export async function grantAllConsents(req: Request, res: Response) {
|
||
try {
|
||
const { hash } = req.params;
|
||
const ipAddress = req.ip || req.socket.remoteAddress || 'unknown';
|
||
|
||
const results = await consentPublicService.grantAllConsentsPublic(hash, ipAddress);
|
||
|
||
// Audit-Log (manuell, da keine Auth-Middleware)
|
||
const customer = await consentPublicService.getCustomerByConsentHash(hash);
|
||
if (customer) {
|
||
for (const type of Object.values(ConsentType)) {
|
||
await createAuditLog({
|
||
userEmail: customer.customer.email || 'public-link',
|
||
action: 'UPDATE',
|
||
sensitivity: 'HIGH',
|
||
resourceType: 'CustomerConsent',
|
||
resourceId: `${customer.customer.id}:${type}`,
|
||
resourceLabel: `Einwilligung ${type} erteilt via Public-Link`,
|
||
endpoint: `/api/public/consent/${hash}/grant`,
|
||
httpMethod: 'POST',
|
||
ipAddress,
|
||
dataSubjectId: customer.customer.id,
|
||
legalBasis: 'DSGVO Art. 6 Abs. 1 lit. a',
|
||
});
|
||
}
|
||
}
|
||
|
||
// Bestätigungs-E-Mail senden
|
||
if (customer?.customer.email) {
|
||
try {
|
||
const systemEmail = await getSystemEmailCredentials();
|
||
if (systemEmail) {
|
||
const consentList = Object.values(ConsentType)
|
||
.map(t => CONSENT_TYPE_LABELS[t]?.label || t)
|
||
.map(label => `<li>${label}</li>`)
|
||
.join('');
|
||
|
||
const confirmationHtml = `
|
||
<div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;">
|
||
<h2 style="color: #16a34a;">Bestätigung Ihrer Einwilligungen</h2>
|
||
<p>Sehr geehrte(r) ${customer.customer.firstName} ${customer.customer.lastName},</p>
|
||
<p>
|
||
vielen Dank! Hiermit bestätigen wir, dass Sie am ${new Date().toLocaleDateString('de-DE', { day: '2-digit', month: '2-digit', year: 'numeric' })}
|
||
folgenden Einwilligungen zugestimmt haben:
|
||
</p>
|
||
<ul style="color: #16a34a;">
|
||
${consentList}
|
||
</ul>
|
||
<p>
|
||
Sie können Ihre Einwilligungen jederzeit über Ihr Kundenportal widerrufen.
|
||
</p>
|
||
<hr style="border: none; border-top: 1px solid #e5e7eb; margin: 24px 0;">
|
||
<p style="color: #9ca3af; font-size: 12px;">
|
||
Hacker-Net Telekommunikation – Stefan Hacker<br>
|
||
Am Wunderburgpark 5b, 26135 Oldenburg<br>
|
||
info@hacker-net.de
|
||
</p>
|
||
</div>
|
||
`;
|
||
|
||
await sendEmail(
|
||
{
|
||
host: systemEmail.smtpServer,
|
||
port: systemEmail.smtpPort,
|
||
user: systemEmail.emailAddress,
|
||
password: systemEmail.password,
|
||
encryption: systemEmail.smtpEncryption,
|
||
allowSelfSignedCerts: systemEmail.allowSelfSignedCerts,
|
||
},
|
||
systemEmail.emailAddress,
|
||
{
|
||
to: customer.customer.email,
|
||
subject: 'Bestätigung Ihrer Datenschutz-Einwilligungen',
|
||
html: confirmationHtml,
|
||
},
|
||
{
|
||
context: 'consent-confirmation',
|
||
customerId: customer.customer.id,
|
||
}
|
||
);
|
||
}
|
||
} catch (emailError) {
|
||
// E-Mail-Fehler soll den Consent-Grant nicht blockieren
|
||
console.error('Bestätigungs-E-Mail konnte nicht gesendet werden:', emailError);
|
||
}
|
||
}
|
||
|
||
res.json({ success: true, data: results });
|
||
} catch (error: any) {
|
||
console.error('Fehler beim Erteilen der Einwilligungen:', error);
|
||
res.status(400).json({ success: false, error: error.message || 'Fehler beim Erteilen' });
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Datenschutzerklärung als PDF
|
||
*/
|
||
export async function getConsentPdf(req: Request, res: Response) {
|
||
try {
|
||
const { hash } = req.params;
|
||
|
||
const result = await consentPublicService.getCustomerByConsentHash(hash);
|
||
if (!result) {
|
||
return res.status(404).json({ success: false, error: 'Ungültiger Link' });
|
||
}
|
||
|
||
const pdfBuffer = await consentPublicService.generateConsentPdf(result.customer.id);
|
||
|
||
res.setHeader('Content-Type', 'application/pdf');
|
||
res.setHeader('Content-Disposition', 'inline; filename="datenschutzerklaerung.pdf"');
|
||
res.send(pdfBuffer);
|
||
} catch (error) {
|
||
console.error('Fehler beim Generieren des PDFs:', error);
|
||
res.status(500).json({ success: false, error: 'Fehler beim Generieren' });
|
||
}
|
||
}
|