|
6 | 6 | from pytz import timezone, UTC |
7 | 7 | from bs4.element import ResultSet # type: ignore |
8 | 8 |
|
9 | | -from circuit_maintenance_parser.parser import Html, Impact, CircuitImpact, Status |
| 9 | +from circuit_maintenance_parser.parser import CircuitImpact, EmailSubjectParser, Html, Impact, Status, Text |
10 | 10 |
|
11 | 11 | logger = logging.getLogger(__name__) |
12 | 12 |
|
13 | 13 | # pylint: disable=too-many-branches |
14 | 14 |
|
15 | 15 |
|
| 16 | +class SubjectParserCogent1(EmailSubjectParser): |
| 17 | + """Subject parser for Cogent nofifications.""" |
| 18 | + |
| 19 | + def parse_subject(self, subject: str): |
| 20 | + """Parse subject. |
| 21 | +
|
| 22 | + Example: |
| 23 | + 11/19/2022 Circuit Provider Maintenance - Edina, MN 1-300123456 |
| 24 | + Correction 06/11/2021 AB987654321-1 Planned Network Maintenance - San Jose, CA 1-123456789 |
| 25 | + """ |
| 26 | + data: Dict = {"circuits": []} |
| 27 | + |
| 28 | + subject = subject.lower() |
| 29 | + |
| 30 | + if subject.startswith("correction") or "rescheduled" in subject: |
| 31 | + data["status"] = Status("RE-SCHEDULED") |
| 32 | + elif "cancellation" in subject: |
| 33 | + data["status"] = Status("CANCELLED") |
| 34 | + elif "planned" in subject or "provider" in subject or "emergency" in subject: |
| 35 | + data["status"] = Status("CONFIRMED") |
| 36 | + elif "completed" in subject: |
| 37 | + data["status"] = Status("COMPLETED") |
| 38 | + else: |
| 39 | + data["status"] = Status("NO-CHANGE") |
| 40 | + |
| 41 | + match = re.search(r".* ([\d-]+)", subject) |
| 42 | + if match: |
| 43 | + circuit_id = match.group(1) |
| 44 | + data["circuits"].append(CircuitImpact(impact=Impact("OUTAGE"), circuit_id=circuit_id.strip())) |
| 45 | + |
| 46 | + return [data] |
| 47 | + |
| 48 | + |
| 49 | +class TextParserCogent1(Text): |
| 50 | + """Parse text body of Cogent emails.""" |
| 51 | + |
| 52 | + def parse_text(self, text): |
| 53 | + """Execute parsing of text. |
| 54 | +
|
| 55 | + Example: |
| 56 | + CIRCUIT PROVIDER MAINTENANCE |
| 57 | +
|
| 58 | + Dear Cogent Customer, |
| 59 | +
|
| 60 | + As a valued customer, Cogent is committed to keeping you informed about any changes in the status of your service with us. This email is to alert you regarding a circuit provider maintenance which will affect your connection to Cogent: |
| 61 | +
|
| 62 | + Start time: 10:00pm CT 11/19/2022 |
| 63 | + End time: 5:00am CT 11/20/2022 |
| 64 | + Work order number: VN16123 |
| 65 | + Order ID(s) impacted: 1-300123456 |
| 66 | + Expected Outage/Downtime: 7 hours |
| 67 | +
|
| 68 | + Cogent customers receiving service in Edina, MN will be affected by this outage. This outage has been scheduled by Zayo. The purpose of this maintenance is to repair damaged fiber. Only the Cogent Order ID(s) above will be impacted. |
| 69 | +
|
| 70 | + During this maintenance window, you will experience an interruption in service while Zayo completes the maintenance activities; the interruption is expected to be less than 7 hours; however, due to the complexity of the work, your downtime may be longer. |
| 71 | +
|
| 72 | + Our network operations engineers closely monitor the work and will do everything possible to minimize any inconvenience to you. If you have any problems with your connection after this time, or if you have any questions regarding the maintenance at any point, please call Customer Support at 1-877-7-COGENT and refer to this Maintenance Ticket: VN16123. |
| 73 | +
|
| 74 | + """ |
| 75 | + data = { |
| 76 | + # "circuits": [], |
| 77 | + "summary": "Cogent circuit maintenance", |
| 78 | + } |
| 79 | + |
| 80 | + lines = text.splitlines() |
| 81 | + |
| 82 | + for line in lines: |
| 83 | + if line.startswith("Dear"): |
| 84 | + match = re.search(r"Dear (.*),", line) |
| 85 | + if match: |
| 86 | + data["account"] = match.group(1) |
| 87 | + elif line.startswith("Start time:"): |
| 88 | + match = re.search(r"Start time: ([A-Za-z\d: ]*) [()A-Za-z\s]+ (\d+/\d+/\d+)", line) |
| 89 | + if match: |
| 90 | + start_str = " ".join(match.groups()) |
| 91 | + elif line.startswith("End time:"): |
| 92 | + match = re.search(r"End time: ([A-Za-z\d: ]*) [()A-Za-z\s]+ (\d+/\d+/\d+)", line) |
| 93 | + if match: |
| 94 | + end_str = " ".join(match.groups()) |
| 95 | + elif line.startswith("Cogent customers receiving service"): |
| 96 | + data["summary"] = line |
| 97 | + match = re.search(r"[^Cogent].*?((\b[A-Z][a-z\s-]+)+, ([A-Za-z-]+[\s-]))", line) |
| 98 | + if match: |
| 99 | + local_timezone = timezone(self._geolocator.city_timezone(match.group(1).strip())) |
| 100 | + |
| 101 | + # set start time using the local city timezone |
| 102 | + try: |
| 103 | + start = datetime.strptime(start_str, "%I:%M %p %d/%m/%Y") |
| 104 | + except ValueError: |
| 105 | + start = datetime.strptime(start_str, "%I:%M%p %d/%m/%Y") |
| 106 | + local_time = local_timezone.localize(start) |
| 107 | + # set start time to UTC |
| 108 | + utc_start = local_time.astimezone(UTC) |
| 109 | + data["start"] = self.dt2ts(utc_start) |
| 110 | + logger.info( |
| 111 | + "Mapped start time %s at %s (%s), to %s (UTC)", |
| 112 | + start_str, |
| 113 | + match.group(1).strip(), |
| 114 | + local_timezone, |
| 115 | + utc_start, |
| 116 | + ) |
| 117 | + # set end time using the local city timezone |
| 118 | + try: |
| 119 | + end = datetime.strptime(end_str, "%I:%M %p %d/%m/%Y") |
| 120 | + except ValueError: |
| 121 | + end = datetime.strptime(end_str, "%I:%M%p %d/%m/%Y") |
| 122 | + local_time = local_timezone.localize(end) |
| 123 | + # set end time to UTC |
| 124 | + utc_end = local_time.astimezone(UTC) |
| 125 | + data["end"] = self.dt2ts(utc_end) |
| 126 | + logger.info( |
| 127 | + "Mapped end time %s at %s (%s), to %s (UTC)", |
| 128 | + end_str, |
| 129 | + match.group(1).strip(), |
| 130 | + local_timezone, |
| 131 | + utc_end, |
| 132 | + ) |
| 133 | + elif line.startswith("Work order number:"): |
| 134 | + match = re.search("Work order number: (.*)", line) |
| 135 | + if match: |
| 136 | + data["maintenance_id"] = match.group(1) |
| 137 | + elif line.startswith("Order ID(s) impacted:"): |
| 138 | + data["circuits"] = [] |
| 139 | + match = re.search(r"Order ID\(s\) impacted: (.*)", line) |
| 140 | + if match: |
| 141 | + for circuit_id in match.group(1).split(","): |
| 142 | + data["circuits"].append(CircuitImpact(impact=Impact("OUTAGE"), circuit_id=circuit_id.strip())) |
| 143 | + elif line.startswith("During this maintenance"): |
| 144 | + data["summary"] = line |
| 145 | + return [data] |
| 146 | + |
| 147 | + |
16 | 148 | class HtmlParserCogent1(Html): |
17 | 149 | """Notifications Parser for Cogent notifications.""" |
18 | 150 |
|
|
0 commit comments