44import re
55from datetime import datetime
66
7- from circuit_maintenance_parser .parser import CircuitImpact , Html , Impact , Status
7+ from circuit_maintenance_parser .parser import CircuitImpact , EmailSubjectParser , Html , Impact , Status
88
99# pylint: disable=too-many-nested-blocks, too-many-branches
1010
@@ -18,7 +18,7 @@ def parse_html(self, soup):
1818 """Execute parsing."""
1919 data = {}
2020 data ["circuits" ] = []
21- data [ "status" ] = Status . CONFIRMED
21+ end_time_explicit = False
2222
2323 for span in soup .find_all ("span" ):
2424 if span .string is None :
@@ -29,6 +29,7 @@ def parse_html(self, soup):
2929 elif span .string .strip () == "End Time:" :
3030 dt_str = span .next_sibling .string .strip ()
3131 data ["end" ] = self .dt2ts (datetime .strptime (dt_str , "%Y-%m-%d %H:%M:%S %z UTC" ))
32+ end_time_explicit = True
3233 elif span .string .strip () == "Peer ASN:" :
3334 data ["account" ] = span .parent .next_sibling .string .strip ()
3435 elif span .string .strip () == "Google Neighbor Address(es):" :
@@ -37,9 +38,42 @@ def parse_html(self, soup):
3738 cid = googleaddr + "-" + span .parent .next_sibling .string .strip ()
3839 data ["circuits" ].append (CircuitImpact (circuit_id = cid , impact = Impact .OUTAGE ))
3940
40- summary = list (soup .find ("div" ).find ("div" ).strings )[- 1 ].strip ()
41- match = re .search (r" - Reference (.*)$" , summary )
42- data ["summary" ] = summary
43- data ["maintenance_id" ] = match [1 ]
41+ # Google sometimes send notifications without End Time specified
42+ if not end_time_explicit and data ["start" ]:
43+ # Since start and end times cannot be equal, manufacturing end date by adding 1hr to start date
44+ end_time_delta = 3600
45+ data ["end" ] = data ["start" ] + end_time_delta
46+
47+ return [data ]
48+
49+
50+ class SubjectParserGoogle1 (EmailSubjectParser ):
51+ """Subject Parser for Google notifications."""
52+
53+ def parse_subject (self , subject ):
54+ """Parse the subject line."""
55+ data = {}
56+
57+ # Example subject format - "[Scheduled] Google Planned Network Maintenance Notification - Reference PCR/123456"
58+ # Group 1: Status (e.g., Scheduled, Completed, Canceled)
59+ # Group 2: Maintenance ID (e.g., PCR/123456)
60+ match = re .search (r"(\[\S+\]).*Reference\s+(\S+)" , subject , re .IGNORECASE | re .DOTALL )
61+ match_2 = re .search (r"\[\S+\]\s+(.*)" , subject , re .IGNORECASE | re .DOTALL )
62+
63+ if match :
64+ status_str = match .group (1 ).upper ()
65+ data ["maintenance_id" ] = match .group (2 ).strip ()
66+ if "COMPLETED" in status_str :
67+ data ["status" ] = Status .COMPLETED
68+ # To handle both Cancelled and Canceled spelling options just in case
69+ elif "CANCEL" in status_str :
70+ data ["status" ] = Status .CANCELLED
71+ elif "SCHEDULED" in status_str :
72+ data ["status" ] = Status .CONFIRMED
73+ # If unable to match, we fallback to default confirmed
74+ else :
75+ data ["status" ] = Status .CONFIRMED
76+ if match_2 :
77+ data ["summary" ] = match_2 .group (1 )
4478
4579 return [data ]
0 commit comments