diff --git a/containers/backupchecks/src/backend/app/main/routes_settings.py b/containers/backupchecks/src/backend/app/main/routes_settings.py index 3de4394..201710c 100644 --- a/containers/backupchecks/src/backend/app/main/routes_settings.py +++ b/containers/backupchecks/src/backend/app/main/routes_settings.py @@ -298,6 +298,160 @@ def settings_jobs_delete_orphaned(): return redirect(url_for("main.settings", section="maintenance")) +@main_bp.route("/settings/test-emails/generate", methods=["POST"]) +@login_required +@roles_required("admin") +def settings_generate_test_emails(): + """Generate test emails in inbox for testing parsers and orphaned jobs cleanup.""" + try: + count_str = request.form.get("count", "5") + try: + count = int(count_str) + count = max(1, min(count, 50)) # Limit between 1 and 50 + except Exception: + count = 5 + + from datetime import datetime, timedelta + import random + + # Template configurations for different backup software + templates = [ + { + "software": "Veeam", + "sender": "veeam@test.local", + "subject_template": "Backup job '{job}' completed {status}", + "body_template": """Job name: {job} +Status: {status} +Start time: {start_time} +End time: {end_time} +Total size: {size} GB +Objects processed: {objects} + +{message} +""", + "statuses": ["successfully", "with warnings", "failed"], + }, + { + "software": "Synology", + "sender": "synology@test.local", + "subject_template": "[Synology] Backup Task {job} {status}", + "body_template": """Dear Administrator, + +Backup task '{job}' has {status}. + +Task: {job} +Status: {status} +Start: {start_time} +Finish: {end_time} +Data transferred: {size} GB + +{message} +""", + "statuses": ["completed successfully", "completed with warnings", "failed"], + }, + { + "software": "NAKIVO", + "sender": "nakivo@test.local", + "subject_template": "Job '{job}' finished {status}", + "body_template": """NAKIVO Backup & Replication + +Job: {job} +Status: {status} +Started: {start_time} +Completed: {end_time} +Size: {size} GB + +{message} +""", + "statuses": ["successfully", "with warnings", "with errors"], + }, + ] + + job_names = [ + "Daily VM Backup", + "Weekly File Server", + "SQL Database Backup", + "Exchange Mailbox", + "Critical Servers", + "Development Environment", + "Production Backup", + "Archive Job", + ] + + messages = { + "successfully": "All backup operations completed without issues.", + "with warnings": "Backup completed but some files were skipped.", + "failed": "Backup failed. Please check the logs for details.", + "with errors": "Some backup objects failed to process.", + } + + created_count = 0 + now = datetime.utcnow() + + for i in range(count): + template = random.choice(templates) + job_name = random.choice(job_names) + status = random.choice(template["statuses"]) + + start_time = now - timedelta(hours=random.randint(1, 24), minutes=random.randint(0, 59)) + end_time = start_time + timedelta(minutes=random.randint(5, 120)) + size = random.randint(10, 500) + objects_count = random.randint(5, 50) + + # Find message for status + message = messages.get(status, messages.get("successfully")) + for key in messages: + if key in status: + message = messages[key] + break + + subject = template["subject_template"].format( + job=job_name, + status=status, + ) + + body = template["body_template"].format( + job=job_name, + status=status, + start_time=start_time.strftime("%Y-%m-%d %H:%M:%S"), + end_time=end_time.strftime("%Y-%m-%d %H:%M:%S"), + size=size, + objects=objects_count, + message=message, + ) + + # Create mail message in inbox + mail = MailMessage( + sender=template["sender"], + subject=subject, + body=body, + text_body=body, + html_body=f"
{body}
", + received_at=start_time, + location="inbox", + job_id=None, + ) + db.session.add(mail) + created_count += 1 + + db.session.commit() + + flash(f"Generated {created_count} test email(s) in inbox.", "success") + + _log_admin_event( + event_type="maintenance_generate_test_emails", + message=f"Generated {created_count} test emails", + details=json.dumps({"count": created_count}), + ) + + except Exception as exc: + db.session.rollback() + print(f"[settings-test] Failed to generate test emails: {exc}") + flash("Failed to generate test emails.", "danger") + + return redirect(url_for("main.settings", section="maintenance")) + + @main_bp.route("/settings/objects/backfill", methods=["POST"]) @login_required @roles_required("admin") diff --git a/containers/backupchecks/src/templates/main/settings.html b/containers/backupchecks/src/templates/main/settings.html index 7d9df5b..3f768b9 100644 --- a/containers/backupchecks/src/templates/main/settings.html +++ b/containers/backupchecks/src/templates/main/settings.html @@ -559,6 +559,24 @@ +
+
+
Generate test emails
+
+

Generate test emails in the inbox for testing parsers and maintenance operations. Emails simulate Veeam, Synology, and NAKIVO backups.

+
+
+ + +
+
+ +
+
+
+
+
+
Jobs maintenance
diff --git a/docs/changelog-claude.md b/docs/changelog-claude.md index f46ffe1..03255e3 100644 --- a/docs/changelog-claude.md +++ b/docs/changelog-claude.md @@ -7,6 +7,7 @@ This file documents all changes made to this project via Claude Code. ### Added - Added "Cleanup orphaned jobs" maintenance option in Settings → Maintenance to delete jobs without valid customer links and their associated emails/runs permanently from database (useful when customers are removed) - Added "Preview orphaned jobs" button to show detailed list of jobs to be deleted with run/email counts before confirming deletion (verification step for safety) +- Added "Generate test emails" feature in Settings → Maintenance to create test emails in inbox that simulate Veeam, Synology, and NAKIVO backup notifications (useful for testing parsers, orphaned jobs cleanup, and other maintenance operations) ### Changed - Removed customer name from Autotask ticket title to keep titles concise (format changed from "[Backupchecks] Customer - Job Name - Status" to "[Backupchecks] Job Name - Status")