wip(phase2): Task 17 - Management-Link in Upload-Erfolg & Rate-Limiter Anpassung
- Task 17: Management-Link im Upload-Erfolg angezeigt mit Copy-Button - Widerruf-Dialoge überarbeitet: Klarstellung zu Scope & Kontakt für Social Media Posts - Rate-Limiter für Dev-Umgebung erhöht (100/h statt 10/h) - Mailto-Link Verhalten noch nicht final getestet (Browser vs. Mail-Client) ACHTUNG: Noch nicht vollständig getestet! Mailto-Funktionalität muss in verschiedenen Browsern validiert werden.
This commit is contained in:
parent
cedc1380dd
commit
e065f2bbc4
|
|
@ -13,7 +13,7 @@ const blockedIPs = new Map(); // IP -> { reason, blockedUntil, failedAttempts
|
||||||
|
|
||||||
// Konfiguration
|
// Konfiguration
|
||||||
const RATE_LIMIT = {
|
const RATE_LIMIT = {
|
||||||
MAX_REQUESTS_PER_HOUR: 10,
|
MAX_REQUESTS_PER_HOUR: process.env.NODE_ENV === 'production' ? 10 : 100, // 100 für Dev, 10 für Production
|
||||||
WINDOW_MS: 60 * 60 * 1000, // 1 Stunde
|
WINDOW_MS: 60 * 60 * 1000, // 1 Stunde
|
||||||
BRUTE_FORCE_THRESHOLD: 20,
|
BRUTE_FORCE_THRESHOLD: 20,
|
||||||
BLOCK_DURATION_MS: 24 * 60 * 60 * 1000 // 24 Stunden
|
BLOCK_DURATION_MS: 24 * 60 * 60 * 1000 // 24 Stunden
|
||||||
|
|
|
||||||
|
|
@ -227,24 +227,43 @@ const ManagementPortalPage = () => {
|
||||||
? 'Werkstatt-Anzeige'
|
? 'Werkstatt-Anzeige'
|
||||||
: group.consents.socialMediaConsents.find(c => c.platformId === platformId)?.platformDisplayName || 'Social Media';
|
: group.consents.socialMediaConsents.find(c => c.platformId === platformId)?.platformDisplayName || 'Social Media';
|
||||||
|
|
||||||
const result = await Swal.fire({
|
if (consentType === 'workshop') {
|
||||||
title: `Einwilligung widerrufen?`,
|
const result = await Swal.fire({
|
||||||
html: `Möchten Sie Ihre Einwilligung für <strong>${consentName}</strong> widerrufen?<br><br>
|
title: `Einwilligung widerrufen?`,
|
||||||
<small>Ihre Bilder werden dann nicht mehr für diesen Zweck verwendet.</small>`,
|
html: `Möchten Sie Ihre Einwilligung für <strong>${consentName}</strong> widerrufen?<br><br>
|
||||||
icon: 'warning',
|
<small>Ihre Bilder werden aus der Werkstatt-Anzeige entfernt.</small>`,
|
||||||
showCancelButton: true,
|
icon: 'warning',
|
||||||
confirmButtonColor: '#d33',
|
showCancelButton: true,
|
||||||
cancelButtonColor: '#3085d6',
|
confirmButtonColor: '#d33',
|
||||||
confirmButtonText: 'Ja, widerrufen',
|
cancelButtonColor: '#3085d6',
|
||||||
cancelButtonText: 'Abbrechen'
|
confirmButtonText: 'Ja, widerrufen',
|
||||||
});
|
cancelButtonText: 'Abbrechen'
|
||||||
|
});
|
||||||
|
|
||||||
if (!result.isConfirmed) return;
|
if (!result.isConfirmed) return;
|
||||||
|
} else {
|
||||||
|
// Social Media Widerruf
|
||||||
|
const result = await Swal.fire({
|
||||||
|
title: `Einwilligung widerrufen?`,
|
||||||
|
html: `Möchten Sie Ihre Einwilligung für <strong>${consentName}</strong> widerrufen?<br><br>
|
||||||
|
<small>Ihre Bilder werden nicht mehr auf ${consentName} veröffentlicht.<br>
|
||||||
|
Bereits veröffentlichte Beiträge bleiben bestehen, aber es werden keine neuen Posts mit Ihren Bildern erstellt.</small>`,
|
||||||
|
icon: 'warning',
|
||||||
|
showCancelButton: true,
|
||||||
|
confirmButtonColor: '#d33',
|
||||||
|
cancelButtonColor: '#3085d6',
|
||||||
|
confirmButtonText: 'Ja, widerrufen',
|
||||||
|
cancelButtonText: 'Abbrechen',
|
||||||
|
footer: `<div style="font-size: 13px; color: #666;">Wenn Sie die Löschung bereits veröffentlichter Beiträge wünschen, kontaktieren Sie uns nach dem Widerruf.</div>`
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!result.isConfirmed) return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const payload = consentType === 'workshop'
|
const payload = consentType === 'workshop'
|
||||||
? { workshopConsent: false }
|
? { consentType: 'workshop', action: 'revoke' }
|
||||||
: { socialMediaConsents: [{ platformId, consented: false }] };
|
: { consentType: 'social_media', action: 'revoke', platformId };
|
||||||
|
|
||||||
const res = await fetch(`/api/manage/${token}/consents`, {
|
const res = await fetch(`/api/manage/${token}/consents`, {
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
|
|
@ -257,13 +276,33 @@ const ManagementPortalPage = () => {
|
||||||
throw new Error(body.error || 'Fehler beim Widerrufen');
|
throw new Error(body.error || 'Fehler beim Widerrufen');
|
||||||
}
|
}
|
||||||
|
|
||||||
await Swal.fire({
|
// Erfolg - zeige Bestätigung mit Kontaktinfo für Social Media
|
||||||
icon: 'success',
|
if (consentType === 'social-media') {
|
||||||
title: 'Einwilligung widerrufen',
|
const mailtoLink = `mailto:it@hobbyhimmel.de?subject=${encodeURIComponent(`Löschung Social Media Post - Gruppe ${group.groupId}`)}&body=${encodeURIComponent(`Hallo,\n\nBitte löschen Sie die bereits veröffentlichten Beiträge meiner Gruppe ${group.groupId} von ${consentName}.\n\nVielen Dank`)}`;
|
||||||
text: `Ihre Einwilligung für ${consentName} wurde widerrufen.`,
|
|
||||||
timer: 2000,
|
await Swal.fire({
|
||||||
showConfirmButton: false
|
icon: 'success',
|
||||||
});
|
title: 'Einwilligung widerrufen',
|
||||||
|
html: `Ihre Einwilligung für ${consentName} wurde widerrufen.<br><br>
|
||||||
|
<div style="background: #f5f5f5; padding: 15px; border-radius: 8px; margin-top: 15px;">
|
||||||
|
<strong>Bereits veröffentlichte Beiträge löschen?</strong><br>
|
||||||
|
<small>Kontaktieren Sie uns mit Ihrer Gruppen-ID:</small><br>
|
||||||
|
<div style="margin-top: 10px;">
|
||||||
|
<strong>Gruppen-ID:</strong> ${group.groupId}<br>
|
||||||
|
<strong>E-Mail:</strong> <span style="color: #1976d2; cursor: pointer;" onclick="window.open='${mailtoLink}'">it@hobbyhimmel.de</span>
|
||||||
|
</div>
|
||||||
|
</div>`,
|
||||||
|
confirmButtonText: 'Verstanden'
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await Swal.fire({
|
||||||
|
icon: 'success',
|
||||||
|
title: 'Einwilligung widerrufen',
|
||||||
|
text: `Ihre Einwilligung für ${consentName} wurde widerrufen.`,
|
||||||
|
timer: 2000,
|
||||||
|
showConfirmButton: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Reload group to get updated consent status
|
// Reload group to get updated consent status
|
||||||
await loadGroup();
|
await loadGroup();
|
||||||
|
|
@ -299,8 +338,8 @@ const ManagementPortalPage = () => {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const payload = consentType === 'workshop'
|
const payload = consentType === 'workshop'
|
||||||
? { workshopConsent: true }
|
? { consentType: 'workshop', action: 'restore' }
|
||||||
: { socialMediaConsents: [{ platformId, consented: true }] };
|
: { consentType: 'social_media', action: 'restore', platformId };
|
||||||
|
|
||||||
const res = await fetch(`/api/manage/${token}/consents`, {
|
const res = await fetch(`/api/manage/${token}/consents`, {
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
|
|
|
||||||
|
|
@ -362,6 +362,80 @@ function MultiUploadPage() {
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
|
{uploadResult?.managementToken && (
|
||||||
|
<Box sx={{
|
||||||
|
bgcolor: 'rgba(255,255,255,0.95)',
|
||||||
|
borderRadius: '8px',
|
||||||
|
p: 2.5,
|
||||||
|
mb: 2,
|
||||||
|
border: '2px solid rgba(255,255,255,0.3)'
|
||||||
|
}}>
|
||||||
|
<Typography sx={{ fontSize: '16px', fontWeight: 'bold', mb: 1.5, color: '#2e7d32' }}>
|
||||||
|
🔗 Verwaltungslink für Ihren Upload
|
||||||
|
</Typography>
|
||||||
|
<Typography sx={{ fontSize: '13px', mb: 1.5, color: '#333' }}>
|
||||||
|
Mit diesem Link können Sie später Ihre Bilder verwalten, Einwilligungen widerrufen oder die Gruppe löschen:
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Box sx={{
|
||||||
|
bgcolor: '#f5f5f5',
|
||||||
|
p: 1.5,
|
||||||
|
borderRadius: '6px',
|
||||||
|
mb: 1.5,
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: 1,
|
||||||
|
flexWrap: 'wrap'
|
||||||
|
}}>
|
||||||
|
<Typography sx={{
|
||||||
|
fontSize: '13px',
|
||||||
|
fontFamily: 'monospace',
|
||||||
|
color: '#1976d2',
|
||||||
|
wordBreak: 'break-all',
|
||||||
|
flex: 1,
|
||||||
|
minWidth: '200px'
|
||||||
|
}}>
|
||||||
|
{window.location.origin}/manage/{uploadResult.managementToken}
|
||||||
|
</Typography>
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
sx={{
|
||||||
|
minWidth: 'auto',
|
||||||
|
px: 2,
|
||||||
|
py: 0.5,
|
||||||
|
fontSize: '12px',
|
||||||
|
textTransform: 'none',
|
||||||
|
bgcolor: '#1976d2',
|
||||||
|
color: 'white',
|
||||||
|
'&:hover': {
|
||||||
|
bgcolor: '#1565c0'
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onClick={() => {
|
||||||
|
const link = `${window.location.origin}/manage/${uploadResult.managementToken}`;
|
||||||
|
navigator.clipboard.writeText(link);
|
||||||
|
Swal.fire({
|
||||||
|
icon: 'success',
|
||||||
|
title: 'Link kopiert!',
|
||||||
|
text: 'Der Verwaltungslink wurde in die Zwischenablage kopiert.',
|
||||||
|
timer: 2000,
|
||||||
|
showConfirmButton: false
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
📋 Kopieren
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Typography sx={{ fontSize: '11px', color: '#666', mb: 0.5 }}>
|
||||||
|
⚠️ <strong>Wichtig:</strong> Bewahren Sie diesen Link sicher auf! Jeder mit diesem Link kann Ihren Upload verwalten.
|
||||||
|
</Typography>
|
||||||
|
<Typography sx={{ fontSize: '11px', color: '#666', fontStyle: 'italic' }}>
|
||||||
|
ℹ️ <strong>Hinweis:</strong> Über diesen Link können Sie nur die Bilder in der Werkstatt verwalten. Bereits auf Social Media Plattformen veröffentlichte Bilder müssen separat dort gelöscht werden.
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
|
||||||
<Typography sx={{ fontSize: '13px', mb: 2, opacity: 0.95 }}>
|
<Typography sx={{ fontSize: '13px', mb: 2, opacity: 0.95 }}>
|
||||||
Die Bilder werden geprüft und nach Freigabe auf dem Werkstatt-Monitor angezeigt.
|
Die Bilder werden geprüft und nach Freigabe auf dem Werkstatt-Monitor angezeigt.
|
||||||
{' '}Bei Social Media Einwilligung werden sie entsprechend veröffentlicht.
|
{' '}Bei Social Media Einwilligung werden sie entsprechend veröffentlicht.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user