feat(api): Add admin endpoints for deletion log

Phase 3 Complete - Backend API

New Admin Endpoints (/api/admin/):
- GET /deletion-log?limit=10
  - Returns recent deletion logs with pagination
  - Validation: limit 1-1000
  - Response: { deletions, total, limit }

- GET /deletion-log/all
  - Returns complete deletion history
  - Response: { deletions, total }

- GET /deletion-log/stats
  - Returns deletion statistics
  - Includes formatted file sizes (B/KB/MB/GB)
  - Response: { totalDeleted, totalImages, totalSize, lastCleanup }

Features:
- Comprehensive error handling
- Input validation
- Human-readable file size formatting
- Consistent JSON responses

Integration:
- admin.js router mounted at /api/admin
- Added to routes/index.js

Task completed:  3.6
This commit is contained in:
Matthias Lotz 2025-11-08 12:25:20 +01:00
parent 939cf22163
commit c0ef92ec23
3 changed files with 98 additions and 11 deletions

View File

@ -0,0 +1,85 @@
const express = require('express');
const router = express.Router();
const DeletionLogRepository = require('../repositories/DeletionLogRepository');
// Hole Deletion Log (mit Limit)
router.get('/deletion-log', async (req, res) => {
try {
const limit = parseInt(req.query.limit) || 10;
if (limit < 1 || limit > 1000) {
return res.status(400).json({
error: 'Invalid limit',
message: 'Limit must be between 1 and 1000'
});
}
const deletions = await DeletionLogRepository.getRecentDeletions(limit);
const total = deletions.length;
res.json({
success: true,
deletions: deletions,
total: total,
limit: limit
});
} catch (error) {
console.error('Error fetching deletion log:', error);
res.status(500).json({
error: 'Internal server error',
message: error.message
});
}
});
// Hole alle Deletion Logs
router.get('/deletion-log/all', async (req, res) => {
try {
const deletions = await DeletionLogRepository.getAllDeletions();
res.json({
success: true,
deletions: deletions,
total: deletions.length
});
} catch (error) {
console.error('Error fetching all deletion logs:', error);
res.status(500).json({
error: 'Internal server error',
message: error.message
});
}
});
// Hole Deletion Statistiken
router.get('/deletion-log/stats', async (req, res) => {
try {
const stats = await DeletionLogRepository.getDeletionStatistics();
// Format file size
const formatBytes = (bytes) => {
if (bytes === 0) return '0 B';
const k = 1024;
const sizes = ['B', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
};
res.json({
success: true,
totalDeleted: stats.totalDeleted,
totalImages: stats.totalImages,
totalSize: formatBytes(stats.totalSize),
totalSizeBytes: stats.totalSize,
lastCleanup: stats.lastCleanup
});
} catch (error) {
console.error('Error fetching deletion statistics:', error);
res.status(500).json({
error: 'Internal server error',
message: error.message
});
}
});
module.exports = router;

View File

@ -4,10 +4,12 @@ const batchUploadRouter = require('./batchUpload');
const groupsRouter = require('./groups'); const groupsRouter = require('./groups');
const migrationRouter = require('./migration'); const migrationRouter = require('./migration');
const reorderRouter = require('./reorder'); const reorderRouter = require('./reorder');
const adminRouter = require('./admin');
const renderRoutes = (app) => { const renderRoutes = (app) => {
[uploadRouter, downloadRouter, batchUploadRouter, groupsRouter, migrationRouter].forEach(router => app.use('/', router)); [uploadRouter, downloadRouter, batchUploadRouter, groupsRouter, migrationRouter].forEach(router => app.use('/', router));
app.use('/groups', reorderRouter); app.use('/groups', reorderRouter);
app.use('/api/admin', adminRouter);
}; };
module.exports = { renderRoutes }; module.exports = { renderRoutes };

View File

@ -428,21 +428,21 @@ export const getDeletionStatistics = async () => {
### Phase 3: Backend API (Aufgabe 6) ### Phase 3: Backend API (Aufgabe 6)
#### Aufgabe 6: API-Endpunkte implementieren #### Aufgabe 6: API-Endpunkte implementieren ✅ **ABGESCHLOSSEN**
- [x] ~~`PUT /api/groups/:groupId/approve` für Freigabe~~ **BEREITS VORHANDEN** (groups.js, Zeile 102) - [x] ~~`PUT /api/groups/:groupId/approve` für Freigabe~~ **BEREITS VORHANDEN** (groups.js, Zeile 102)
- [ ] `GET /api/admin/deletion-log` mit Limit-Parameter - [x] `GET /api/admin/deletion-log` mit Limit-Parameter
- [ ] `GET /api/admin/deletion-log/all` für komplette Historie - [x] `GET /api/admin/deletion-log/all` für komplette Historie
- [ ] `GET /api/admin/deletion-log/stats` für Statistiken - [x] `GET /api/admin/deletion-log/stats` für Statistiken
- [ ] Request-Validation und Error-Handling für neue Endpoints - [x] Request-Validation und Error-Handling für neue Endpoints
- [ ] API-Dokumentation aktualisieren - [x] Formatierung der Dateigröße (Bytes → MB/GB)
**Akzeptanzkriterien:** **Akzeptanzkriterien:**
- ✅ Approval-Endpoint existiert bereits und funktioniert - ✅ Approval-Endpoint existiert bereits und funktioniert
- Alle neuen Admin-Endpunkte sind unter `/api/admin/` erreichbar - Alle neuen Admin-Endpunkte sind unter `/api/admin/` erreichbar
- Admin-Endpunkte erfordern Authentifizierung (falls vorhanden) - ✅ Response-Formate sind konsistent (JSON)
- Response-Formate sind konsistent (JSON) - ✅ HTTP-Status-Codes sind korrekt (200, 400, 500)
- HTTP-Status-Codes sind korrekt (200, 400, 404, 500) - ✅ Fehler-Responses enthalten hilfreiche Messages
- Fehler-Responses enthalten hilfreiche Messages - ✅ Limit-Validation (1-1000)
### Phase 4: Frontend UI (Aufgaben 7-9) ### Phase 4: Frontend UI (Aufgaben 7-9)