feat(testing): Add cleanup testing tools and API endpoints
- Add POST /api/admin/cleanup/trigger for manual cleanup - Add GET /api/admin/cleanup/preview for dry-run testing - Create test-cleanup.sh (bash) for easy testing - Create test-cleanup.js (node) as alternative test tool - Enable backdating groups for testing purposes
This commit is contained in:
parent
3a2efd97c3
commit
861d4813d1
|
|
@ -1,6 +1,9 @@
|
|||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const DeletionLogRepository = require('../repositories/DeletionLogRepository');
|
||||
const GroupCleanupService = require('../services/GroupCleanupService');
|
||||
|
||||
const cleanupService = new GroupCleanupService();
|
||||
|
||||
// Hole Deletion Log (mit Limit)
|
||||
router.get('/deletion-log', async (req, res) => {
|
||||
|
|
@ -82,4 +85,53 @@ router.get('/deletion-log/stats', async (req, res) => {
|
|||
}
|
||||
});
|
||||
|
||||
// Manueller Cleanup-Trigger (für Testing)
|
||||
router.post('/cleanup/trigger', async (req, res) => {
|
||||
try {
|
||||
console.log('[Admin API] Manual cleanup triggered');
|
||||
const result = await cleanupService.performScheduledCleanup();
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
result: result,
|
||||
message: `Cleanup completed: ${result.deletedGroups} groups deleted`
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('[Admin API] Error triggering cleanup:', error);
|
||||
res.status(500).json({
|
||||
error: 'Internal server error',
|
||||
message: error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Zeige welche Gruppen gelöscht würden (Dry-Run)
|
||||
router.get('/cleanup/preview', async (req, res) => {
|
||||
try {
|
||||
const groups = await cleanupService.findGroupsForDeletion();
|
||||
|
||||
// Berechne Tage bis zur Löschung für jede Gruppe
|
||||
const groupsWithDays = groups.map(group => ({
|
||||
...group,
|
||||
daysUntilDeletion: cleanupService.getDaysUntilDeletion(group.uploadDate)
|
||||
}));
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
groupsToDelete: groupsWithDays.length,
|
||||
groups: groupsWithDays,
|
||||
message: groupsWithDays.length === 0
|
||||
? 'No groups would be deleted'
|
||||
: `${groupsWithDays.length} groups would be deleted`
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('[Admin API] Error previewing cleanup:', error);
|
||||
res.status(500).json({
|
||||
error: 'Internal server error',
|
||||
message: error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
module.exports = router;
|
||||
|
|
|
|||
255
backend/src/scripts/test-cleanup.js
Executable file
255
backend/src/scripts/test-cleanup.js
Executable file
|
|
@ -0,0 +1,255 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Test-Script für automatisches Löschen
|
||||
*
|
||||
* Dieses Script hilft beim Testen des Cleanup-Features:
|
||||
* 1. Zeigt alle nicht-freigegebenen Gruppen
|
||||
* 2. Erlaubt das Zurückdatieren von Gruppen (für Tests)
|
||||
* 3. Zeigt Preview der zu löschenden Gruppen
|
||||
* 4. Triggert manuellen Cleanup
|
||||
*/
|
||||
|
||||
const readline = require('readline');
|
||||
const https = require('http');
|
||||
|
||||
const rl = readline.createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout
|
||||
});
|
||||
|
||||
const API_BASE = 'http://localhost:5001';
|
||||
|
||||
// Helper: HTTP Request
|
||||
function makeRequest(path, method = 'GET', data = null) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const url = new URL(path, API_BASE);
|
||||
const options = {
|
||||
hostname: url.hostname,
|
||||
port: url.port,
|
||||
path: url.pathname + url.search,
|
||||
method: method,
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
};
|
||||
|
||||
const req = https.request(options, (res) => {
|
||||
let body = '';
|
||||
res.on('data', chunk => body += chunk);
|
||||
res.on('end', () => {
|
||||
try {
|
||||
resolve(JSON.parse(body));
|
||||
} catch (e) {
|
||||
resolve(body);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
req.on('error', reject);
|
||||
|
||||
if (data) {
|
||||
req.write(JSON.stringify(data));
|
||||
}
|
||||
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
|
||||
// Helper: SQL Query über API
|
||||
async function execSQL(query) {
|
||||
// Direkt über docker exec
|
||||
const { exec } = require('child_process');
|
||||
return new Promise((resolve, reject) => {
|
||||
exec(
|
||||
`docker compose -f docker/dev/docker-compose.yml exec -T backend-dev sqlite3 /usr/src/app/src/data/db/image_uploader.db "${query}"`,
|
||||
(error, stdout, stderr) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
resolve(stdout);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// Zeige Menü
|
||||
function showMenu() {
|
||||
console.log('\n========================================');
|
||||
console.log(' CLEANUP TEST MENÜ');
|
||||
console.log('========================================');
|
||||
console.log('1. Zeige alle nicht-freigegebenen Gruppen');
|
||||
console.log('2. Gruppe um X Tage zurückdatieren (für Tests)');
|
||||
console.log('3. Preview: Welche Gruppen würden gelöscht?');
|
||||
console.log('4. Cleanup JETZT ausführen');
|
||||
console.log('5. Lösch-Historie anzeigen');
|
||||
console.log('0. Beenden');
|
||||
console.log('========================================\n');
|
||||
}
|
||||
|
||||
// Option 1: Zeige nicht-freigegebene Gruppen
|
||||
async function showUnapprovedGroups() {
|
||||
console.log('\n📋 Lade nicht-freigegebene Gruppen...\n');
|
||||
const result = await execSQL(
|
||||
'SELECT group_id, year, name, approved, datetime(upload_date) as upload_date, ' +
|
||||
'CAST((julianday(\\'now\\') - julianday(upload_date)) AS INTEGER) as days_old ' +
|
||||
'FROM groups WHERE approved = 0 ORDER BY upload_date DESC;'
|
||||
);
|
||||
|
||||
console.log('Gruppe ID | Jahr | Name | Freigegeben | Upload-Datum | Tage alt');
|
||||
console.log('------------- | ---- | --------- | ----------- | -------------------- | --------');
|
||||
console.log(result || 'Keine nicht-freigegebenen Gruppen gefunden.');
|
||||
}
|
||||
|
||||
// Option 2: Gruppe zurückdatieren
|
||||
async function backdateGroup() {
|
||||
await showUnapprovedGroups();
|
||||
|
||||
rl.question('\nGruppe ID zum Zurückdatieren: ', async (groupId) => {
|
||||
if (!groupId) {
|
||||
console.log('❌ Keine Gruppe ID angegeben');
|
||||
return mainMenu();
|
||||
}
|
||||
|
||||
rl.question('Um wie viele Tage zurückdatieren? (z.B. 8 für 8 Tage alt): ', async (days) => {
|
||||
const daysNum = parseInt(days);
|
||||
if (isNaN(daysNum) || daysNum < 1) {
|
||||
console.log('❌ Ungültige Anzahl Tage');
|
||||
return mainMenu();
|
||||
}
|
||||
|
||||
try {
|
||||
await execSQL(
|
||||
`UPDATE groups SET upload_date = datetime('now', '-${daysNum} days') WHERE group_id = '${groupId}';`
|
||||
);
|
||||
console.log(`✅ Gruppe ${groupId} wurde um ${daysNum} Tage zurückdatiert`);
|
||||
|
||||
// Zeige aktualisierte Info
|
||||
const result = await execSQL(
|
||||
`SELECT group_id, datetime(upload_date) as upload_date, ` +
|
||||
`CAST((julianday('now') - julianday(upload_date)) AS INTEGER) as days_old ` +
|
||||
`FROM groups WHERE group_id = '${groupId}';`
|
||||
);
|
||||
console.log('\nAktualisierte Daten:');
|
||||
console.log(result);
|
||||
} catch (error) {
|
||||
console.error('❌ Fehler:', error.message);
|
||||
}
|
||||
|
||||
mainMenu();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Option 3: Preview Cleanup
|
||||
async function previewCleanup() {
|
||||
console.log('\n🔍 Lade Cleanup Preview...\n');
|
||||
try {
|
||||
const result = await makeRequest('/api/admin/cleanup/preview');
|
||||
|
||||
if (result.groupsToDelete === 0) {
|
||||
console.log('✅ Keine Gruppen würden gelöscht (alle sind < 7 Tage alt oder freigegeben)');
|
||||
} else {
|
||||
console.log(`⚠️ ${result.groupsToDelete} Gruppe(n) würden gelöscht:\n`);
|
||||
result.groups.forEach(group => {
|
||||
console.log(` - ${group.group_id} (${group.year}) - ${group.name}`);
|
||||
console.log(` Upload: ${group.uploadDate}`);
|
||||
console.log(` Tage seit Upload: ${Math.abs(group.daysUntilDeletion)}`);
|
||||
console.log('');
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ Fehler:', error.message);
|
||||
}
|
||||
|
||||
mainMenu();
|
||||
}
|
||||
|
||||
// Option 4: Cleanup ausführen
|
||||
async function executeCleanup() {
|
||||
console.log('\n⚠️ ACHTUNG: Dies wird Gruppen permanent löschen!\n');
|
||||
|
||||
rl.question('Cleanup wirklich ausführen? (ja/nein): ', async (answer) => {
|
||||
if (answer.toLowerCase() !== 'ja') {
|
||||
console.log('❌ Abgebrochen');
|
||||
return mainMenu();
|
||||
}
|
||||
|
||||
console.log('\n🔄 Führe Cleanup aus...\n');
|
||||
try {
|
||||
const result = await makeRequest('/api/admin/cleanup/trigger', 'POST');
|
||||
|
||||
console.log('✅ Cleanup abgeschlossen!');
|
||||
console.log(` Gelöschte Gruppen: ${result.result.deletedGroups}`);
|
||||
console.log(` Fehler: ${result.result.failedGroups || 0}`);
|
||||
} catch (error) {
|
||||
console.error('❌ Fehler:', error.message);
|
||||
}
|
||||
|
||||
mainMenu();
|
||||
});
|
||||
}
|
||||
|
||||
// Option 5: Lösch-Historie
|
||||
async function showDeletionLog() {
|
||||
console.log('\n📜 Lösch-Historie (letzte 10 Einträge)...\n');
|
||||
try {
|
||||
const result = await makeRequest('/api/admin/deletion-log?limit=10');
|
||||
|
||||
if (result.deletions.length === 0) {
|
||||
console.log('Keine Einträge im Lösch-Log');
|
||||
} else {
|
||||
console.log('Gruppe ID | Jahr | Bilder | Upload-Datum | Gelöscht am | Grund');
|
||||
console.log('------------- | ---- | ------ | -------------------- | -------------------- | -----');
|
||||
result.deletions.forEach(d => {
|
||||
console.log(
|
||||
`${d.group_id.padEnd(13)} | ${String(d.year).padEnd(4)} | ${String(d.image_count).padEnd(6)} | ` +
|
||||
`${d.upload_date.substring(0, 19)} | ${d.deleted_at.substring(0, 19)} | ${d.deletion_reason}`
|
||||
);
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ Fehler:', error.message);
|
||||
}
|
||||
|
||||
mainMenu();
|
||||
}
|
||||
|
||||
// Hauptmenü
|
||||
function mainMenu() {
|
||||
showMenu();
|
||||
rl.question('Wähle eine Option: ', async (choice) => {
|
||||
switch (choice) {
|
||||
case '1':
|
||||
await showUnapprovedGroups();
|
||||
mainMenu();
|
||||
break;
|
||||
case '2':
|
||||
await backdateGroup();
|
||||
break;
|
||||
case '3':
|
||||
await previewCleanup();
|
||||
break;
|
||||
case '4':
|
||||
await executeCleanup();
|
||||
break;
|
||||
case '5':
|
||||
await showDeletionLog();
|
||||
break;
|
||||
case '0':
|
||||
console.log('\n👋 Auf Wiedersehen!\n');
|
||||
rl.close();
|
||||
process.exit(0);
|
||||
break;
|
||||
default:
|
||||
console.log('❌ Ungültige Option');
|
||||
mainMenu();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Start
|
||||
console.log('\n🚀 Cleanup Test Script gestartet\n');
|
||||
console.log('Hinweis: Stelle sicher, dass der Dev-Server läuft (./dev.sh)');
|
||||
mainMenu();
|
||||
99
test-cleanup.sh
Executable file
99
test-cleanup.sh
Executable file
|
|
@ -0,0 +1,99 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Cleanup Test Helper Script
|
||||
# Hilft beim Testen des automatischen Löschens
|
||||
|
||||
echo "========================================"
|
||||
echo " CLEANUP TEST HELPER"
|
||||
echo "========================================"
|
||||
echo ""
|
||||
|
||||
# Prüfe ob Container läuft
|
||||
if ! docker compose -f docker/dev/docker-compose.yml ps | grep -q "backend-dev.*Up"; then
|
||||
echo "❌ Backend-Container läuft nicht. Bitte starte ./dev.sh"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
function show_unapproved_groups() {
|
||||
echo "📋 Nicht-freigegebene Gruppen:"
|
||||
echo ""
|
||||
docker compose -f docker/dev/docker-compose.yml exec -T backend-dev sqlite3 /usr/src/app/src/data/db/image_uploader.db \
|
||||
"SELECT group_id || ' | Jahr: ' || year || ' | Name: ' || name || ' | Upload: ' || datetime(upload_date) || ' | Tage: ' || CAST((julianday('now') - julianday(upload_date)) AS INTEGER)
|
||||
FROM groups WHERE approved = 0 ORDER BY upload_date DESC;"
|
||||
echo ""
|
||||
}
|
||||
|
||||
function backdate_group() {
|
||||
show_unapproved_groups
|
||||
|
||||
echo ""
|
||||
read -p "Gruppe ID zum Zurückdatieren: " group_id
|
||||
read -p "Um wie viele Tage? (z.B. 8): " days
|
||||
|
||||
docker compose -f docker/dev/docker-compose.yml exec -T backend-dev sqlite3 /usr/src/app/src/data/db/image_uploader.db \
|
||||
"UPDATE groups SET upload_date = datetime('now', '-$days days') WHERE group_id = '$group_id';"
|
||||
|
||||
echo "✅ Gruppe $group_id wurde um $days Tage zurückdatiert"
|
||||
echo ""
|
||||
|
||||
# Zeige aktualisierte Info
|
||||
docker compose -f docker/dev/docker-compose.yml exec -T backend-dev sqlite3 /usr/src/app/src/data/db/image_uploader.db \
|
||||
"SELECT 'Gruppe: ' || group_id || ', Upload: ' || datetime(upload_date) || ', Tage alt: ' || CAST((julianday('now') - julianday(upload_date)) AS INTEGER)
|
||||
FROM groups WHERE group_id = '$group_id';"
|
||||
echo ""
|
||||
}
|
||||
|
||||
function preview_cleanup() {
|
||||
echo "🔍 Cleanup Preview (über API):"
|
||||
echo ""
|
||||
curl -s http://localhost:5001/api/admin/cleanup/preview | jq '.'
|
||||
echo ""
|
||||
}
|
||||
|
||||
function trigger_cleanup() {
|
||||
echo "⚠️ ACHTUNG: Dies wird Gruppen permanent löschen!"
|
||||
echo ""
|
||||
read -p "Cleanup wirklich ausführen? (ja/nein): " confirm
|
||||
|
||||
if [ "$confirm" != "ja" ]; then
|
||||
echo "❌ Abgebrochen"
|
||||
return
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "🔄 Führe Cleanup aus..."
|
||||
echo ""
|
||||
curl -s -X POST http://localhost:5001/api/admin/cleanup/trigger | jq '.'
|
||||
echo ""
|
||||
}
|
||||
|
||||
function show_deletion_log() {
|
||||
echo "📜 Lösch-Historie (letzte 10):"
|
||||
echo ""
|
||||
curl -s http://localhost:5001/api/admin/deletion-log?limit=10 | jq '.deletions[] | "Gruppe: \(.group_id), Jahr: \(.year), Bilder: \(.image_count), Gelöscht: \(.deleted_at)"'
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Menü
|
||||
while true; do
|
||||
echo "Optionen:"
|
||||
echo " 1) Zeige nicht-freigegebene Gruppen"
|
||||
echo " 2) Gruppe zurückdatieren (für Tests)"
|
||||
echo " 3) Preview: Was würde gelöscht?"
|
||||
echo " 4) Cleanup JETZT ausführen"
|
||||
echo " 5) Lösch-Historie anzeigen"
|
||||
echo " 0) Beenden"
|
||||
echo ""
|
||||
read -p "Wähle Option: " option
|
||||
echo ""
|
||||
|
||||
case $option in
|
||||
1) show_unapproved_groups ;;
|
||||
2) backdate_group ;;
|
||||
3) preview_cleanup ;;
|
||||
4) trigger_cleanup ;;
|
||||
5) show_deletion_log ;;
|
||||
0) echo "👋 Auf Wiedersehen!"; exit 0 ;;
|
||||
*) echo "❌ Ungültige Option" ;;
|
||||
esac
|
||||
done
|
||||
Loading…
Reference in New Issue
Block a user