Handle 3CX update mails as informational runs

This commit is contained in:
Ivo Oskamp 2026-02-19 13:27:52 +01:00
parent 3c629bb664
commit 441f5a8e50
4 changed files with 32 additions and 3 deletions

7
.gitignore vendored
View File

@ -1,2 +1,9 @@
# Claude Code confidential files
.claude/
# Codex local workspace files
.codex/
# Python cache artifacts
__pycache__/
*.pyc

View File

@ -679,6 +679,8 @@ def _infer_schedule_map_from_runs(job_id: int):
return schedule
if bs == 'qnap' and bt == 'firmware update':
return schedule
if bs == '3cx' and bt == 'update':
return schedule
if bs == 'syncovery' and bt == 'syncovery':
return schedule
except Exception:
@ -994,4 +996,3 @@ def _next_ticket_code(now_utc: datetime) -> str:
seq = 1
return f"{prefix}{seq:04d}"

View File

@ -24,6 +24,10 @@ def try_parse_3cx(msg: MailMessage) -> Tuple[bool, Dict, List[Dict]]:
- SSL Certificate Renewal (informational)
Subject: '3CX Notification: SSL Certificate Renewal - <host>'
Body contains an informational message about the renewal.
- Update Successful (informational)
Subject: '3CX Notification: Update Successful - <host>'
Body confirms update completion and healthy services.
"""
subject = (msg.subject or "").strip()
if not subject:
@ -38,11 +42,16 @@ def try_parse_3cx(msg: MailMessage) -> Tuple[bool, Dict, List[Dict]]:
subject,
flags=re.IGNORECASE,
)
m_update = re.match(
r"^3CX Notification:\s*Update Successful\s*-\s*(.+)$",
subject,
flags=re.IGNORECASE,
)
if not m_backup and not m_ssl:
if not m_backup and not m_ssl and not m_update:
return False, {}, []
job_name = (m_backup or m_ssl).group(1).strip()
job_name = (m_backup or m_ssl or m_update).group(1).strip()
body = (getattr(msg, "text_body", None) or getattr(msg, "body", None) or "")
if not body:
@ -60,6 +69,17 @@ def try_parse_3cx(msg: MailMessage) -> Tuple[bool, Dict, List[Dict]]:
}
return True, result, []
# Update successful: store as tracked informational run
if m_update:
result = {
"backup_software": "3CX",
"backup_type": "Update",
"job_name": job_name,
"overall_status": "Success",
"overall_message": body or None,
}
return True, result, []
# Backup complete
backup_file = None
m_file = re.search(r"^\s*Backup\s+name\s*:\s*(.+?)\s*$", body, flags=re.IGNORECASE | re.MULTILINE)

View File

@ -12,6 +12,7 @@ This file documents all changes made to this project via Claude Code.
- Approved Jobs import now only applies `autotask_company_id` and `autotask_company_name` when the import option is checked
- Customers CSV import now only applies Autotask mapping fields when the import option is checked
- Import success and audit output now includes whether Autotask IDs were imported
- 3CX parser now recognizes `3CX Notification: Update Successful - <host>` as an informational run with `backup_software: 3CX`, `backup_type: Update`, and `overall_status: Success`, and excludes this type from schedule inference (no Expected/Missed generation)
## [2026-02-16]