diff --git a/docker/dev/frontend/nginx.conf b/docker/dev/frontend/nginx.conf
index 33c7a0d..f36c6aa 100644
--- a/docker/dev/frontend/nginx.conf
+++ b/docker/dev/frontend/nginx.conf
@@ -107,20 +107,6 @@ server {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
- # Protected routes - Admin (password protected) - React Dev Server
- location /admin {
- auth_basic "Restricted Area - Admin";
- auth_basic_user_file /etc/nginx/.htpasswd;
-
- proxy_pass http://127.0.0.1:3000;
- proxy_http_version 1.1;
- proxy_set_header Upgrade $http_upgrade;
- proxy_set_header Connection "Upgrade";
- proxy_set_header Host $host;
- proxy_set_header X-Real-IP $remote_addr;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- }
-
# Protected routes - Moderation (password protected) - React Dev Server
location /moderation {
auth_basic "Restricted Area - Moderation";
diff --git a/docker/prod/frontend/nginx.conf b/docker/prod/frontend/nginx.conf
index d5f8c3d..eba988c 100644
--- a/docker/prod/frontend/nginx.conf
+++ b/docker/prod/frontend/nginx.conf
@@ -141,20 +141,6 @@ http {
add_header X-Robots-Tag "noindex, nofollow, nosnippet, noarchive" always;
}
- # Protected routes - Admin (password protected)
- location /admin {
- auth_basic "Restricted Area - Admin";
- auth_basic_user_file /etc/nginx/.htpasswd;
-
- root /usr/share/nginx/html;
- index index.html index.htm;
- try_files $uri $uri/ /index.html;
- expires -1;
-
- # Prevent indexing
- add_header X-Robots-Tag "noindex, nofollow, nosnippet, noarchive" always;
- }
-
# Protected routes - Moderation (password protected)
location /moderation {
auth_basic "Restricted Area - Moderation";
diff --git a/frontend/src/App.js b/frontend/src/App.js
index f2c8fc3..9f60ec2 100644
--- a/frontend/src/App.js
+++ b/frontend/src/App.js
@@ -8,7 +8,6 @@ import GroupsOverviewPage from './Components/Pages/GroupsOverviewPage';
import ModerationGroupsPage from './Components/Pages/ModerationGroupsPage';
import ModerationGroupImagesPage from './Components/Pages/ModerationGroupImagesPage';
import PublicGroupImagesPage from './Components/Pages/PublicGroupImagesPage';
-import DeletionLogPage from './Components/Pages/DeletionLogPage';
import FZF from './Components/Pages/404Page.js'
function App() {
@@ -21,7 +20,6 @@ function App() {
} />
} />
} />
- } />
} />
diff --git a/frontend/src/Components/ComponentUtils/DeletionLogSection.js b/frontend/src/Components/ComponentUtils/DeletionLogSection.js
new file mode 100644
index 0000000..4af3458
--- /dev/null
+++ b/frontend/src/Components/ComponentUtils/DeletionLogSection.js
@@ -0,0 +1,264 @@
+import React, { useState, useEffect } from 'react';
+import {
+ Card,
+ Typography,
+ Button,
+ Box,
+ Table,
+ TableBody,
+ TableCell,
+ TableContainer,
+ TableHead,
+ TableRow,
+ Paper,
+ Chip,
+ Grid,
+ CircularProgress
+} from '@mui/material';
+import DeleteIcon from '@mui/icons-material/Delete';
+import WarningIcon from '@mui/icons-material/Warning';
+import InfoIcon from '@mui/icons-material/Info';
+
+const DeletionLogSection = () => {
+ const [deletions, setDeletions] = useState([]);
+ const [statistics, setStatistics] = useState(null);
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState(null);
+ const [showAll, setShowAll] = useState(false);
+
+ useEffect(() => {
+ loadDeletionLog();
+ loadStatistics();
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [showAll]);
+
+ const loadDeletionLog = async () => {
+ try {
+ setLoading(true);
+ const endpoint = showAll
+ ? '/api/admin/deletion-log/all'
+ : '/api/admin/deletion-log?limit=10';
+
+ const response = await fetch(endpoint);
+
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`);
+ }
+
+ const data = await response.json();
+ setDeletions(data.deletions || []);
+ setError(null);
+ } catch (error) {
+ console.error('Fehler beim Laden des Lösch-Logs:', error);
+ setError('Fehler beim Laden des Lösch-Logs');
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ const loadStatistics = async () => {
+ try {
+ const response = await fetch('/api/admin/deletion-log/stats');
+
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`);
+ }
+
+ const data = await response.json();
+ setStatistics(data.statistics || null);
+ } catch (error) {
+ console.error('Fehler beim Laden der Statistiken:', error);
+ }
+ };
+
+ const formatDate = (dateString) => {
+ if (!dateString) return '-';
+ const date = new Date(dateString);
+ return date.toLocaleString('de-DE', {
+ year: 'numeric',
+ month: '2-digit',
+ day: '2-digit',
+ hour: '2-digit',
+ minute: '2-digit'
+ });
+ };
+
+ const formatFileSize = (bytes) => {
+ if (!bytes || bytes === 0) return '0 KB';
+
+ const k = 1024;
+ const sizes = ['Bytes', 'KB', 'MB', 'GB'];
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
+
+ return `${(bytes / Math.pow(k, i)).toFixed(2)} ${sizes[i]}`;
+ };
+
+ const getReasonIcon = (reason) => {
+ if (reason && reason.includes('unapproved')) {
+ return ;
+ }
+ return ;
+ };
+
+ if (loading) {
+ return (
+
+
+
+ Lade Lösch-Historie...
+
+
+ );
+ }
+
+ return (
+
+
+
+
+ Lösch-Historie
+
+
+ Automatisch gelöschte Gruppen (nicht innerhalb von 7 Tagen freigegeben)
+
+
+
+ {error && (
+
+ {error}
+
+ )}
+
+ {/* Statistics Cards */}
+ {statistics && (
+
+
+
+
+ {statistics.totalGroupsDeleted || 0}
+
+
+ Gelöschte Gruppen
+
+
+
+
+
+
+ {statistics.totalImagesDeleted || 0}
+
+
+ Gelöschte Bilder
+
+
+
+
+
+
+ {statistics.totalStorageFreed || '0 KB'}
+
+
+ Speicher freigegeben
+
+
+
+
+ )}
+
+ {/* Toggle Button */}
+
+
+ {showAll ? 'Alle Einträge' : 'Letzte 10 Einträge'}
+
+ setShowAll(!showAll)}
+ startIcon={ }
+ >
+ {showAll ? 'Nur letzte 10' : 'Alle anzeigen'}
+
+
+
+ {/* Deletion Log Table */}
+ {deletions.length === 0 ? (
+
+
+
+ Keine Lösch-Einträge gefunden
+
+
+ Es wurden bisher keine Gruppen automatisch gelöscht.
+
+
+ ) : (
+
+
+
+
+ Gruppe ID
+ Jahr
+ Bilder
+ Upload-Datum
+ Gelöscht am
+ Grund
+ Größe
+
+
+
+ {deletions.map((row) => (
+
+
+
+
+ {row.year || '-'}
+ {row.image_count || 0}
+ {formatDate(row.upload_date)}
+ {formatDate(row.deleted_at)}
+
+
+ {getReasonIcon(row.deletion_reason)}
+
+ {row.deletion_reason || 'Unbekannt'}
+
+
+
+
+
+ {formatFileSize(row.total_file_size)}
+
+
+
+ ))}
+
+
+
+ )}
+
+ {/* Info Box */}
+
+
+
+
+
+ Automatische Löschung
+
+
+ Der Cleanup läuft täglich um 10:00 Uhr. Gruppen, die nicht innerhalb von 7 Tagen
+ freigegeben werden, werden automatisch gelöscht. Alle Lösch-Vorgänge werden hier protokolliert.
+
+
+
+
+
+ );
+};
+
+export default DeletionLogSection;
diff --git a/frontend/src/Components/ComponentUtils/Headers/Navbar.js b/frontend/src/Components/ComponentUtils/Headers/Navbar.js
index 968cde7..bc8f5a7 100644
--- a/frontend/src/Components/ComponentUtils/Headers/Navbar.js
+++ b/frontend/src/Components/ComponentUtils/Headers/Navbar.js
@@ -4,7 +4,7 @@ import { NavLink } from 'react-router-dom'
import '../Css/Navbar.css'
import logo from '../../../Images/logo.png'
-import { Lock as LockIcon, AdminPanelSettings as AdminIcon } from '@mui/icons-material';
+import { Lock as LockIcon } from '@mui/icons-material';
function Navbar() {
return (
@@ -15,7 +15,6 @@ function Navbar() {
Groups
Slideshow
Moderation
- Lösch-Log
Upload
About
diff --git a/frontend/src/Components/Pages/DeletionLogPage.js b/frontend/src/Components/Pages/DeletionLogPage.js
deleted file mode 100644
index bd4ae29..0000000
--- a/frontend/src/Components/Pages/DeletionLogPage.js
+++ /dev/null
@@ -1,285 +0,0 @@
-import React, { useState, useEffect } from 'react';
-import { Helmet } from 'react-helmet';
-import {
- Container,
- Card,
- Typography,
- Button,
- Box,
- CircularProgress,
- Table,
- TableBody,
- TableCell,
- TableContainer,
- TableHead,
- TableRow,
- Paper,
- Chip,
- Grid
-} from '@mui/material';
-import DeleteIcon from '@mui/icons-material/Delete';
-import WarningIcon from '@mui/icons-material/Warning';
-import InfoIcon from '@mui/icons-material/Info';
-import Navbar from '../ComponentUtils/Headers/Navbar';
-import Footer from '../ComponentUtils/Footer';
-
-const DeletionLogPage = () => {
- const [deletions, setDeletions] = useState([]);
- const [statistics, setStatistics] = useState(null);
- const [loading, setLoading] = useState(true);
- const [error, setError] = useState(null);
- const [showAll, setShowAll] = useState(false);
-
- useEffect(() => {
- loadDeletionLog();
- loadStatistics();
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [showAll]);
-
- const loadDeletionLog = async () => {
- try {
- setLoading(true);
- const endpoint = showAll
- ? '/api/admin/deletion-log/all'
- : '/api/admin/deletion-log?limit=10';
-
- const response = await fetch(endpoint);
-
- if (!response.ok) {
- throw new Error(`HTTP error! status: ${response.status}`);
- }
-
- const data = await response.json();
- setDeletions(data.deletions || []);
- setError(null);
- } catch (error) {
- console.error('Fehler beim Laden des Lösch-Logs:', error);
- setError('Fehler beim Laden des Lösch-Logs');
- } finally {
- setLoading(false);
- }
- };
-
- const loadStatistics = async () => {
- try {
- const response = await fetch('/api/admin/deletion-log/stats');
-
- if (!response.ok) {
- throw new Error(`HTTP error! status: ${response.status}`);
- }
-
- const data = await response.json();
- setStatistics(data.statistics || null);
- } catch (error) {
- console.error('Fehler beim Laden der Statistiken:', error);
- }
- };
-
- const formatDate = (dateString) => {
- if (!dateString) return '-';
- const date = new Date(dateString);
- return date.toLocaleString('de-DE', {
- year: 'numeric',
- month: '2-digit',
- day: '2-digit',
- hour: '2-digit',
- minute: '2-digit'
- });
- };
-
- const getReasonIcon = (reason) => {
- if (reason.includes('unapproved')) {
- return ;
- }
- return ;
- };
-
- if (loading) {
- return (
-
-
-
-
-
-
- Lade Lösch-Historie...
-
-
-
-
-
- );
- }
-
- return (
-
-
- Lösch-Historie - Image Uploader
-
-
-
-
-
-
- Lösch-Historie
-
-
- Übersicht über automatisch gelöschte Gruppen
-
-
-
- {error && (
-
- {error}
-
- )}
-
- {/* Statistics Cards */}
- {statistics && (
-
-
-
-
- {statistics.totalGroupsDeleted || 0}
-
-
- Gelöschte Gruppen
-
-
-
-
-
-
- {statistics.totalImagesDeleted || 0}
-
-
- Gelöschte Bilder
-
-
-
-
-
-
- {statistics.totalStorageFreed || '0 KB'}
-
-
- Speicher freigegeben
-
-
-
-
- )}
-
- {/* Toggle Button */}
-
-
- {showAll ? 'Alle Einträge' : 'Letzte 10 Einträge'}
-
- setShowAll(!showAll)}
- startIcon={ }
- >
- {showAll ? 'Nur letzte 10 anzeigen' : 'Alle anzeigen'}
-
-
-
- {/* Deletion Log Table */}
- {deletions.length === 0 ? (
-
-
-
- Keine Lösch-Einträge gefunden
-
-
- Es wurden bisher keine Gruppen automatisch gelöscht.
-
-
- ) : (
-
-
-
-
- Gruppe ID
- Jahr
- Bilder
- Upload-Datum
- Gelöscht am
- Grund
- Größe
-
-
-
- {deletions.map((row) => (
-
-
-
-
- {row.year || '-'}
- {row.image_count || 0}
- {formatDate(row.upload_date)}
- {formatDate(row.deleted_at)}
-
-
- {getReasonIcon(row.deletion_reason)}
-
- {row.deletion_reason || 'Unbekannt'}
-
-
-
-
-
- {formatFileSize(row.total_file_size)}
-
-
-
- ))}
-
-
-
- )}
-
- {/* Info Box */}
-
-
-
-
-
- Hinweis zur automatischen Löschung
-
-
- Gruppen, die nicht innerhalb von 7 Tagen nach dem Upload freigegeben werden,
- werden automatisch gelöscht. Der Cleanup läuft täglich um 10:00 Uhr.
- Alle Lösch-Vorgänge werden hier protokolliert (ohne personenbezogene Daten).
-
-
-
-
-
-
-
- );
-};
-
-// Helper function for file size formatting
-const formatFileSize = (bytes) => {
- if (!bytes || bytes === 0) return '0 KB';
-
- const k = 1024;
- const sizes = ['Bytes', 'KB', 'MB', 'GB'];
- const i = Math.floor(Math.log(bytes) / Math.log(k));
-
- return `${(bytes / Math.pow(k, i)).toFixed(2)} ${sizes[i]}`;
-};
-
-export default DeletionLogPage;
diff --git a/frontend/src/Components/Pages/ModerationGroupsPage.js b/frontend/src/Components/Pages/ModerationGroupsPage.js
index edf82c6..d26fe8e 100644
--- a/frontend/src/Components/Pages/ModerationGroupsPage.js
+++ b/frontend/src/Components/Pages/ModerationGroupsPage.js
@@ -6,6 +6,7 @@ import Swal from 'sweetalert2/dist/sweetalert2.js';
import Navbar from '../ComponentUtils/Headers/Navbar';
import Footer from '../ComponentUtils/Footer';
import ImageGallery from '../ComponentUtils/ImageGallery';
+import DeletionLogSection from '../ComponentUtils/DeletionLogSection';
import { getImageSrc } from '../../Utils/imageUtils';
const ModerationGroupsPage = () => {
@@ -221,6 +222,11 @@ const ModerationGroupsPage = () => {
/>
+ {/* Lösch-Historie */}
+
+
{/* Bilder-Modal */}
{showImages && selectedGroup && (