From 19ef9dc32adef3014f0710fd14ca97962ed15bba Mon Sep 17 00:00:00 2001 From: Ivo Oskamp Date: Mon, 9 Feb 2026 14:44:19 +0100 Subject: [PATCH] Update test email generator with fixed sets and separate buttons Changed from configurable count input to three separate buttons for success, warning, and error test emails. Each button generates exactly 3 emails with consistent data for reproducible testing. Changes: - Updated routes_settings.py to use fixed email sets instead of random data - Changed route from /settings/test-emails/generate to /settings/test-emails/generate/ - Created three predefined email sets (success, warning, error) with fixed content - Updated settings.html UI to show three separate buttons instead of count input - Each set contains 3 emails simulating Veeam, Synology, and NAKIVO backups - Updated changelog with detailed description Co-Authored-By: Claude Sonnet 4.5 --- .../src/backend/app/main/routes_settings.py | 254 ++++++++++-------- .../src/templates/main/settings.html | 22 +- docs/changelog-claude.md | 2 +- 3 files changed, 153 insertions(+), 125 deletions(-) diff --git a/containers/backupchecks/src/backend/app/main/routes_settings.py b/containers/backupchecks/src/backend/app/main/routes_settings.py index 201710c..df989d7 100644 --- a/containers/backupchecks/src/backend/app/main/routes_settings.py +++ b/containers/backupchecks/src/backend/app/main/routes_settings.py @@ -298,136 +298,162 @@ def settings_jobs_delete_orphaned(): return redirect(url_for("main.settings", section="maintenance")) -@main_bp.route("/settings/test-emails/generate", methods=["POST"]) +@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.""" +def settings_generate_test_emails(status_type): + """Generate test emails in inbox for testing parsers and orphaned jobs cleanup. + + Fixed sets for consistent testing and reproducibility. + """ 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} + # Fixed test email sets per status type + email_sets = { + "success": [ + { + "from_address": "veeam@test.local", + "subject": "Backup job 'Daily VM Backup' completed successfully", + "body": """Job name: Daily VM Backup +Status: Success +Start time: 2026-02-09 01:00:00 +End time: 2026-02-09 02:15:00 +Total size: 150 GB +Objects processed: 25 -{message} -""", - "statuses": ["successfully", "with warnings", "failed"], - }, - { - "software": "Synology", - "sender": "synology@test.local", - "subject_template": "[Synology] Backup Task {job} {status}", - "body_template": """Dear Administrator, +All backup operations completed without issues.""", + }, + { + "from_address": "synology@test.local", + "subject": "[Synology] Backup Task SQL Database Backup completed successfully", + "body": """Dear Administrator, -Backup task '{job}' has {status}. +Backup task 'SQL Database Backup' has completed successfully. -Task: {job} -Status: {status} -Start: {start_time} -Finish: {end_time} -Data transferred: {size} GB +Task: SQL Database Backup +Status: Success +Start: 2026-02-09 02:00:00 +Finish: 2026-02-09 02:45:00 +Data transferred: 75 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 +All backup operations completed without issues.""", + }, + { + "from_address": "nakivo@test.local", + "subject": "Job 'Exchange Mailbox' finished successfully", + "body": """NAKIVO Backup & Replication -Job: {job} -Status: {status} -Started: {start_time} -Completed: {end_time} -Size: {size} GB +Job: Exchange Mailbox +Status: Success +Started: 2026-02-09 03:00:00 +Completed: 2026-02-09 03:30:00 +Size: 50 GB -{message} -""", - "statuses": ["successfully", "with warnings", "with errors"], - }, - ] +All backup operations completed without issues.""", + }, + ], + "warning": [ + { + "from_address": "veeam@test.local", + "subject": "Backup job 'Weekly File Server' completed with warnings", + "body": """Job name: Weekly File Server +Status: Warning +Start time: 2026-02-09 01:00:00 +End time: 2026-02-09 02:30:00 +Total size: 200 GB +Objects processed: 35 - job_names = [ - "Daily VM Backup", - "Weekly File Server", - "SQL Database Backup", - "Exchange Mailbox", - "Critical Servers", - "Development Environment", - "Production Backup", - "Archive Job", - ] +Backup completed but some files were skipped.""", + }, + { + "from_address": "synology@test.local", + "subject": "[Synology] Backup Task Critical Servers completed with warnings", + "body": """Dear Administrator, - 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.", +Backup task 'Critical Servers' has completed with warnings. + +Task: Critical Servers +Status: Warning +Start: 2026-02-09 02:00:00 +Finish: 2026-02-09 03:00:00 +Data transferred: 300 GB + +Backup completed but some files were skipped.""", + }, + { + "from_address": "nakivo@test.local", + "subject": "Job 'Production Backup' finished with warnings", + "body": """NAKIVO Backup & Replication + +Job: Production Backup +Status: Warning +Started: 2026-02-09 03:00:00 +Completed: 2026-02-09 04:00:00 +Size: 250 GB + +Some backup objects were skipped.""", + }, + ], + "error": [ + { + "from_address": "veeam@test.local", + "subject": "Backup job 'Development Environment' failed", + "body": """Job name: Development Environment +Status: Failed +Start time: 2026-02-09 01:00:00 +End time: 2026-02-09 01:15:00 +Total size: 0 GB +Objects processed: 0 + +Backup failed. Please check the logs for details.""", + }, + { + "from_address": "synology@test.local", + "subject": "[Synology] Backup Task Archive Job failed", + "body": """Dear Administrator, + +Backup task 'Archive Job' has failed. + +Task: Archive Job +Status: Failed +Start: 2026-02-09 02:00:00 +Finish: 2026-02-09 02:05:00 +Data transferred: 0 GB + +Backup failed. Please check the logs for details.""", + }, + { + "from_address": "nakivo@test.local", + "subject": "Job 'Critical Servers' finished with errors", + "body": """NAKIVO Backup & Replication + +Job: Critical Servers +Status: Failed +Started: 2026-02-09 03:00:00 +Completed: 2026-02-09 03:10:00 +Size: 0 GB + +Some backup objects failed to process.""", + }, + ], } + if status_type not in email_sets: + flash("Invalid status type.", "danger") + return redirect(url_for("main.settings", section="maintenance")) + + emails = email_sets[status_type] 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 + for email_data in emails: mail = MailMessage( - sender=template["sender"], - subject=subject, - body=body, - text_body=body, - html_body=f"
{body}
", - received_at=start_time, + from_address=email_data["from_address"], + subject=email_data["subject"], + text_body=email_data["body"], + html_body=f"
{email_data['body']}
", + received_at=now - timedelta(hours=created_count), location="inbox", job_id=None, ) @@ -436,12 +462,12 @@ Size: {size} GB db.session.commit() - flash(f"Generated {created_count} test email(s) in inbox.", "success") + flash(f"Generated {created_count} {status_type} 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}), + message=f"Generated {created_count} {status_type} test emails", + details=json.dumps({"status_type": status_type, "count": created_count}), ) except Exception as exc: diff --git a/containers/backupchecks/src/templates/main/settings.html b/containers/backupchecks/src/templates/main/settings.html index 3f768b9..2254fc6 100644 --- a/containers/backupchecks/src/templates/main/settings.html +++ b/containers/backupchecks/src/templates/main/settings.html @@ -563,16 +563,18 @@
Generate test emails
-

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

-
-
- - -
-
- -
-
+

Generate fixed test email sets in the inbox for testing parsers and maintenance operations. Each set contains 3 emails simulating Veeam, Synology, and NAKIVO backups.

+
+
+ +
+
+ +
+
+ +
+
diff --git a/docs/changelog-claude.md b/docs/changelog-claude.md index 03255e3..2334075 100644 --- a/docs/changelog-claude.md +++ b/docs/changelog-claude.md @@ -7,7 +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) +- Added "Generate test emails" feature in Settings → Maintenance with three separate buttons to create fixed test email sets (success/warning/error) in inbox for testing parsers and maintenance operations (each set contains exactly 3 emails simulating Veeam, Synology, and NAKIVO backup notifications with consistent data for reproducible testing) ### 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")