Auto-commit local changes before build (2026-01-13 16:30:32)
This commit is contained in:
parent
934a495867
commit
fd0051cb29
@ -1 +1 @@
|
||||
v20260113-08-vspc-object-linking
|
||||
v20260113-08-vspc-object-linking-normalize
|
||||
|
||||
@ -68,4 +68,53 @@ def find_matching_job(msg: MailMessage) -> Optional[Job]:
|
||||
if len(matches) == 1:
|
||||
return matches[0]
|
||||
|
||||
# Backwards-compatible matching for Veeam VSPC Active Alarms summary per-company jobs.
|
||||
# Earlier versions could store company names with slightly different whitespace / HTML entities,
|
||||
# while parsers store objects using a normalized company prefix. When the exact match fails,
|
||||
# try a normalized company comparison so existing jobs continue to match.
|
||||
try:
|
||||
bsw = (backup or "").strip().lower()
|
||||
bt = (btype or "").strip().lower()
|
||||
jn = (job_name or "").strip()
|
||||
if bsw == "veeam" and bt == "service provider console" and "|" in jn:
|
||||
left, right = [p.strip() for p in jn.split("|", 1)]
|
||||
if left.lower() == "active alarms summary" and right:
|
||||
from .parsers.veeam import normalize_vspc_company_name # lazy import
|
||||
|
||||
target_company = normalize_vspc_company_name(right)
|
||||
if not target_company:
|
||||
return None
|
||||
|
||||
q2 = Job.query
|
||||
if norm_from is None:
|
||||
q2 = q2.filter(Job.from_address.is_(None))
|
||||
else:
|
||||
q2 = q2.filter(Job.from_address == norm_from)
|
||||
q2 = q2.filter(Job.backup_software == backup)
|
||||
q2 = q2.filter(Job.backup_type == btype)
|
||||
q2 = q2.filter(Job.job_name.ilike("Active alarms summary | %"))
|
||||
|
||||
# Load a small set of candidates and compare the company portion.
|
||||
candidates = q2.order_by(Job.updated_at.desc(), Job.id.desc()).limit(25).all()
|
||||
normalized_matches: list[Job] = []
|
||||
for cand in candidates:
|
||||
cand_name = (cand.job_name or "").strip()
|
||||
if "|" not in cand_name:
|
||||
continue
|
||||
c_left, c_right = [p.strip() for p in cand_name.split("|", 1)]
|
||||
if c_left.lower() != "active alarms summary" or not c_right:
|
||||
continue
|
||||
if normalize_vspc_company_name(c_right) == target_company:
|
||||
normalized_matches.append(cand)
|
||||
|
||||
if len(normalized_matches) > 1:
|
||||
customer_ids = {m.customer_id for m in normalized_matches}
|
||||
if len(customer_ids) == 1:
|
||||
return normalized_matches[0]
|
||||
return None
|
||||
if len(normalized_matches) == 1:
|
||||
return normalized_matches[0]
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return None
|
||||
|
||||
@ -228,45 +228,6 @@ def _parse_vspc_active_alarms_from_html(html: str) -> Tuple[List[Dict], str, Opt
|
||||
return objects, overall_status, overall_message
|
||||
|
||||
|
||||
def extract_vspc_active_alarms_companies(raw: str) -> List[str]:
|
||||
"""Extract company names with alarms > 0 from a VSPC Active Alarms summary body."""
|
||||
if not raw:
|
||||
return []
|
||||
|
||||
txt = raw
|
||||
if "<" in txt and ">" in txt:
|
||||
txt = re.sub(r"<[^>]+>", " ", txt)
|
||||
txt = _html.unescape(txt)
|
||||
txt = txt.replace("\xa0", " ")
|
||||
txt = re.sub(r"\s+", " ", txt).strip()
|
||||
|
||||
seen: set[str] = set()
|
||||
out: List[str] = []
|
||||
|
||||
for m in re.finditer(
|
||||
r"\bCompany:\s*([^\(\r\n]+?)\s*\(\s*alarms?\s*:\s*(\d+)\s*\)",
|
||||
txt,
|
||||
flags=re.IGNORECASE,
|
||||
):
|
||||
cname = (m.group(1) or "").strip()
|
||||
cname = cname.replace("\xa0", " ")
|
||||
cname = re.sub(r"\s+", " ", cname).strip()
|
||||
try:
|
||||
alarms = int(m.group(2))
|
||||
except Exception:
|
||||
alarms = 0
|
||||
|
||||
if not cname or alarms <= 0:
|
||||
continue
|
||||
if cname in seen:
|
||||
continue
|
||||
seen.add(cname)
|
||||
out.append(cname)
|
||||
|
||||
return out
|
||||
|
||||
|
||||
|
||||
def _parse_cloud_connect_report_from_html(html: str) -> Tuple[List[Dict], str]:
|
||||
"""Parse Veeam Cloud Connect daily report (provider) HTML.
|
||||
|
||||
|
||||
@ -62,6 +62,15 @@
|
||||
- Uses case-insensitive matching for "<company> | <object>" mail objects.
|
||||
- Added best-effort retroactive processing after approving VSPC company mappings to automatically link older inbox messages that are now fully mapped.
|
||||
|
||||
---
|
||||
|
||||
## v20260113-08-vspc-object-linking-normalize
|
||||
|
||||
- Fixed duplicate definition of the VSPC Active Alarms company extraction logic, which caused inconsistent company normalization.
|
||||
- Ensured consistent company name normalization is used when creating per-company VSPC jobs and when linking objects to those jobs.
|
||||
- Improved object linking for VSPC Active Alarms so real objects (e.g. HV01, USB Disk) are correctly associated with their jobs.
|
||||
- Restored automatic re-linking of previously approved companies and objects for new and historical VSPC mails.
|
||||
- Added backward-compatible matching to prevent existing VSPC jobs from breaking due to earlier inconsistent company naming.
|
||||
***
|
||||
|
||||
## v0.1.20
|
||||
|
||||
Loading…
Reference in New Issue
Block a user