From 489e2166bbf4ec3b43b39fb7a9545fc601a5a8d6 Mon Sep 17 00:00:00 2001 From: "matthias.lotz" Date: Sun, 30 Nov 2025 11:20:10 +0100 Subject: [PATCH] feat(telegram): add daily deletion warning cron job (Phase 5) - Added Telegram warning cron job at 09:00 (1 hour before cleanup) - Integrated with GroupCleanupService.findGroupsForDeletion() - Sends sendDeletionWarning() notification for groups pending deletion - Added manual trigger method triggerTelegramWarningNow() for development - Added POST /api/admin/telegram/warning endpoint for manual testing - Fixed SchedulerService singleton instance in server.js app.set() - Added Telegram ENV vars to docker-compose.yml environment section Tested successfully with test data showing warning message in Telegram. --- backend/docs/openapi.json | 43 +++++++++++++++ backend/src/routes/admin.js | 40 ++++++++++++++ backend/src/server.js | 3 ++ backend/src/services/SchedulerService.js | 68 +++++++++++++++++++++++- docker/dev/docker-compose.yml | 3 ++ 5 files changed, 156 insertions(+), 1 deletion(-) diff --git a/backend/docs/openapi.json b/backend/docs/openapi.json index a6c2fe5..4fb3d61 100644 --- a/backend/docs/openapi.json +++ b/backend/docs/openapi.json @@ -39,6 +39,9 @@ { "name": "Admin - Cleanup" }, + { + "name": "Admin - Telegram" + }, { "name": "Admin - Monitoring" }, @@ -1726,6 +1729,46 @@ } } }, + "/api/admin/telegram/warning": { + "post": { + "tags": [ + "Admin - Telegram" + ], + "summary": "Manually trigger Telegram deletion warning", + "description": "Sends deletion warning to Telegram for testing (normally runs daily at 09:00)", + "responses": { + "200": { + "description": "Warning sent successfully", + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "groupsWarned": { + "type": "number", + "example": 2 + }, + "message": { + "type": "string", + "example": "Deletion warning sent for 2 groups" + } + }, + "xml": { + "name": "main" + } + } + }, + "403": { + "description": "Forbidden" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, "/api/admin/cleanup/preview": { "get": { "tags": [ diff --git a/backend/src/routes/admin.js b/backend/src/routes/admin.js index 6582a00..82a40ac 100644 --- a/backend/src/routes/admin.js +++ b/backend/src/routes/admin.js @@ -237,6 +237,46 @@ router.post('/cleanup/trigger', async (req, res) => { } }); +router.post('/telegram/warning', async (req, res) => { + /* + #swagger.tags = ['Admin - Telegram'] + #swagger.summary = 'Manually trigger Telegram deletion warning' + #swagger.description = 'Sends deletion warning to Telegram for testing (normally runs daily at 09:00)' + #swagger.responses[200] = { + description: 'Warning sent successfully', + schema: { + success: true, + groupsWarned: 2, + message: 'Deletion warning sent for 2 groups' + } + } + */ + try { + const schedulerService = req.app.get('schedulerService'); + + if (!schedulerService) { + return res.status(500).json({ + success: false, + message: 'Scheduler service not available' + }); + } + + const result = await schedulerService.triggerTelegramWarningNow(); + + res.json({ + success: true, + groupsWarned: result.groupCount, + message: result.message + }); + } catch (error) { + console.error('[Admin API] Error triggering Telegram warning:', error); + res.status(500).json({ + error: 'Internal server error', + message: error.message + }); + } +}); + router.get('/cleanup/preview', async (req, res) => { /* #swagger.tags = ['Admin - Cleanup'] diff --git a/backend/src/server.js b/backend/src/server.js index 2b73cc1..f49dfac 100644 --- a/backend/src/server.js +++ b/backend/src/server.js @@ -82,6 +82,9 @@ class Server { console.log(`✅ Server läuft auf Port ${this._port}`); console.log(`📊 SQLite Datenbank aktiv`); + // Speichere SchedulerService in app für Admin-Endpoints + this._app.set('schedulerService', SchedulerService); + // Starte Scheduler für automatisches Cleanup SchedulerService.start(); diff --git a/backend/src/services/SchedulerService.js b/backend/src/services/SchedulerService.js index 5d23193..5b7f713 100644 --- a/backend/src/services/SchedulerService.js +++ b/backend/src/services/SchedulerService.js @@ -1,9 +1,11 @@ const cron = require('node-cron'); const GroupCleanupService = require('./GroupCleanupService'); +const TelegramNotificationService = require('./TelegramNotificationService'); class SchedulerService { constructor() { this.tasks = []; + this.telegramService = new TelegramNotificationService(); } start() { @@ -30,7 +32,35 @@ class SchedulerService { this.tasks.push(cleanupTask); - console.log('✓ Scheduler started - Daily cleanup at 10:00 AM (Europe/Berlin)'); + // Telegram Warning-Job: Jeden Tag um 09:00 Uhr (1 Stunde vor Cleanup) + const telegramWarningTask = cron.schedule('0 9 * * *', async () => { + console.log('[Scheduler] Running daily Telegram deletion warning at 09:00 AM...'); + try { + if (this.telegramService.isAvailable()) { + const groupsForDeletion = await GroupCleanupService.findGroupsForDeletion(); + + if (groupsForDeletion && groupsForDeletion.length > 0) { + await this.telegramService.sendDeletionWarning(groupsForDeletion); + console.log(`[Scheduler] Sent deletion warning for ${groupsForDeletion.length} groups`); + } else { + console.log('[Scheduler] No groups pending deletion'); + } + } else { + console.log('[Scheduler] Telegram service not available, skipping warning'); + } + } catch (error) { + console.error('[Scheduler] Telegram warning task failed:', error); + } + }, { + scheduled: true, + timezone: "Europe/Berlin" + }); + + this.tasks.push(telegramWarningTask); + + console.log('✓ Scheduler started:'); + console.log(' - Daily cleanup at 10:00 AM (Europe/Berlin)'); + console.log(' - Daily Telegram warning at 09:00 AM (Europe/Berlin)'); // Für Development: Manueller Trigger if (process.env.NODE_ENV === 'development') { @@ -50,6 +80,42 @@ class SchedulerService { console.log('[Scheduler] Manual cleanup triggered...'); return await GroupCleanupService.performScheduledCleanup(); } + + // Für Development: Manueller Telegram-Warning-Trigger + async triggerTelegramWarningNow() { + console.log('[Scheduler] Manual Telegram warning triggered...'); + try { + if (!this.telegramService.isAvailable()) { + console.log('[Scheduler] Telegram service not available'); + return { success: false, message: 'Telegram service not available' }; + } + + const groupsForDeletion = await GroupCleanupService.findGroupsForDeletion(); + + if (!groupsForDeletion || groupsForDeletion.length === 0) { + console.log('[Scheduler] No groups pending deletion'); + return { success: true, message: 'No groups pending deletion', groupCount: 0 }; + } + + await this.telegramService.sendDeletionWarning(groupsForDeletion); + console.log(`[Scheduler] Sent deletion warning for ${groupsForDeletion.length} groups`); + + return { + success: true, + message: `Warning sent for ${groupsForDeletion.length} groups`, + groupCount: groupsForDeletion.length, + groups: groupsForDeletion.map(g => ({ + groupId: g.groupId, + name: g.name, + year: g.year, + uploadDate: g.uploadDate + })) + }; + } catch (error) { + console.error('[Scheduler] Manual Telegram warning failed:', error); + return { success: false, message: error.message }; + } + } } module.exports = new SchedulerService(); diff --git a/docker/dev/docker-compose.yml b/docker/dev/docker-compose.yml index cf8d18c..de75389 100644 --- a/docker/dev/docker-compose.yml +++ b/docker/dev/docker-compose.yml @@ -46,6 +46,9 @@ services: - ENABLE_HOST_RESTRICTION=true - TRUST_PROXY_HOPS=0 - PUBLIC_UPLOAD_RATE_LIMIT=20 + - TELEGRAM_ENABLED=true + - TELEGRAM_BOT_TOKEN=8496813818:AAHShJP_cqOuWIW66ROUCxa-1C83CCCZmqU + - TELEGRAM_CHAT_ID=-1003064825033 networks: - dev-internal command: [ "npm", "run", "server" ]