diff --git a/aastatus_to_webhook.py b/aastatus_to_webhook.py index 23248f1..ad33521 100644 --- a/aastatus_to_webhook.py +++ b/aastatus_to_webhook.py @@ -17,7 +17,7 @@ FEED_URL = "https://aastatus.net/atom.cgi" WEBHOOK_URL = "https://discord.com/api/webhooks/XXXXXXX" # Discord webhook URL STATE_FILE = Path("/tmp/aaisp_atom_state.json") -# Event colors (default fallbacks) +# Event colors COLOR_MINOR_OPEN = 0xFFFF00 # yellow COLOR_MAJOR_OPEN = 0xFF0000 # red COLOR_CLOSED = 0x2ECC71 # green @@ -54,7 +54,9 @@ def fetch_feed(url): raise -def get_first_valid_entry(feed_xml): +def parse_feed_entries(feed_xml): + """Return a list of all valid entries in the feed.""" + entries = [] try: root = ET.fromstring(feed_xml) atom_ns = "{http://www.w3.org/2005/Atom}" @@ -104,7 +106,7 @@ def get_first_valid_entry(feed_xml): updated = entry.findtext(f"{atom_ns}updated", "") published = entry.findtext(f"{atom_ns}published", "") - return { + entries.append({ "id": id_elem.text.strip(), "title": html.unescape(title_text), "link": link, @@ -114,9 +116,9 @@ def get_first_valid_entry(feed_xml): "severity": severity, "status": status, "content": html.unescape(content_text) - } + }) - return None + return entries except ET.ParseError as e: logger.error(f"XML parsing error: {e}") @@ -134,26 +136,18 @@ def html_to_markdown(html_content): return md.strip()[:3500] -### COLOR LOGIC (refactored, table-driven) ### +### COLOR LOGIC (table-driven) ### def get_event_color(status, severity): - """ - Determines the Discord embed colour based on status & severity. - Uses a lookup table for clarity and easy extensions. - """ - - # Special case colours for Planned Maintenance (PEW) SPECIAL_COLORS = { ("PEW", "Open"): 0x51D3D4, ("PEW", "Planned"): 0x51D3D4, } - # Direct match first key = (severity, status) if key in SPECIAL_COLORS: return SPECIAL_COLORS[key] - # Normal rules if status == "Closed": return COLOR_CLOSED @@ -212,51 +206,51 @@ def main(): logger.info("[*] Fetching feed...") feed_xml = fetch_feed(FEED_URL) - logger.info("[*] Parsing...") - entry = get_first_valid_entry(feed_xml) - if not entry: - logger.warning("No entry found") + logger.info("[*] Parsing feed entries...") + entries = parse_feed_entries(feed_xml) + if not entries: + logger.warning("No entries found") return - incident_id = entry["id"] state = load_state() - prev = state.get(incident_id) + for entry in entries: + incident_id = entry["id"] + prev = state.get(incident_id) - # Determine if an update is needed - must_post = False - change_type = "New entry" + must_post = False + change_type = "New entry" - if prev is None: - must_post = True - change_type = "New Incident Detected" - else: - # Compare important fields - if entry["status"] != prev.get("status"): + if prev is None: must_post = True - change_type = f"Status changed: {prev.get('status')} → {entry['status']}" - elif entry["severity"] != prev.get("severity"): - must_post = True - change_type = f"Severity changed: {prev.get('severity']} → {entry['severity']}" - elif entry["updated"] != prev.get("updated"): - must_post = True - change_type = "Feed updated" - elif entry["content"] != prev.get("content"): - must_post = True - change_type = "Content updated" + change_type = "New Incident Detected" + else: + if entry["status"] != prev.get("status"): + must_post = True + change_type = f"Status changed: {prev.get('status')} → {entry['status']}" + elif entry["severity"] != prev.get("severity"): + must_post = True + change_type = f"Severity changed: {prev.get('severity')} → {entry['severity']}" + elif entry["updated"] != prev.get("updated"): + must_post = True + change_type = "Feed updated" + elif entry["content"] != prev.get("content"): + must_post = True + change_type = "Content updated" - if must_post: - logger.info(f"[+] Posting update: {change_type}") - payload = build_discord_payload(entry, change_type) - post_to_discord(WEBHOOK_URL, payload) + if must_post: + logger.info(f"[+] Posting update: {change_type} ({entry['title']})") + payload = build_discord_payload(entry, change_type) + post_to_discord(WEBHOOK_URL, payload) + + # Save state + state[incident_id] = { + "status": entry["status"], + "severity": entry["severity"], + "updated": entry["updated"], + "content": entry["content"] + } - # Save state no matter what - state[incident_id] = { - "status": entry["status"], - "severity": entry["severity"], - "updated": entry["updated"], - "content": entry["content"] - } save_state(state)