From c51bd86f0162795534f1314a9a0e170798eac819 Mon Sep 17 00:00:00 2001 From: Mark Kekez <92973272+aliex-13@users.noreply.github.com> Date: Mon, 9 Sep 2024 14:38:27 +0930 Subject: [PATCH] Update Windstream Parser for new emails (#291) * Search again for start/end and maint_id * Add test for new Windstream email * Fix Pylint issues * Fix doctest issue --- .../parsers/windstream.py | 41 +++++++++---------- tests/unit/data/windstream/windstream2.eml | 10 +++++ .../data/windstream/windstream2_result.json | 19 +++++++++ tests/unit/test_e2e.py | 7 ++++ 4 files changed, 55 insertions(+), 22 deletions(-) create mode 100644 tests/unit/data/windstream/windstream2.eml create mode 100644 tests/unit/data/windstream/windstream2_result.json diff --git a/circuit_maintenance_parser/parsers/windstream.py b/circuit_maintenance_parser/parsers/windstream.py index e0e18879..898f7943 100644 --- a/circuit_maintenance_parser/parsers/windstream.py +++ b/circuit_maintenance_parser/parsers/windstream.py @@ -41,28 +41,25 @@ def parse_html(self, soup): data["summary"] = summary_text - table = soup.find("table") - for row in table.find_all("tr"): - if len(row) < 2: - continue - cols = row.find_all("td") - header_tag = cols[0].string - if header_tag is None or header_tag == "Maintenance Address:": - continue - header_tag = header_tag.string.strip() - value_tag = cols[1].string.strip() - if header_tag == "WMT:": - data["maintenance_id"] = value_tag - elif "Date & Time:" in header_tag: - dt_time = convert_timezone(value_tag) - if "Event Start" in header_tag: - data["start"] = int(dt_time.replace(tzinfo=timezone.utc).timestamp()) - elif "Event End" in header_tag: - data["end"] = int(dt_time.replace(tzinfo=timezone.utc).timestamp()) - elif header_tag == "Outage": - impact = Impact("OUTAGE") - else: - continue + impact = soup.find("td", string="Outage").find_next_sibling("td").string + if impact: + impact = Impact("OUTAGE") + + maint_id = soup.find("td", string="WMT:").find_next_sibling("td").string + if maint_id: + data["maintenance_id"] = maint_id + + event = soup.find("td", string="Event Start Date & Time:").find_next_sibling("td").string + if event: + dt_time = convert_timezone(event) + data["start"] = int(dt_time.replace(tzinfo=timezone.utc).timestamp()) + event = "" + + event = soup.find("td", string="Event End Date & Time:").find_next_sibling("td").string + if event: + dt_time = convert_timezone(event) + data["end"] = int(dt_time.replace(tzinfo=timezone.utc).timestamp()) + event = "" table = soup.find("table", "circuitTable") for row in table.find_all("tr"): diff --git a/tests/unit/data/windstream/windstream2.eml b/tests/unit/data/windstream/windstream2.eml new file mode 100644 index 00000000..56f01bc8 --- /dev/null +++ b/tests/unit/data/windstream/windstream2.eml @@ -0,0 +1,10 @@ +From: wci.maintenance.notifications@windstream.com +To: receiver@testing.com +Date: 6 Aug 2024 20:42:43 +0000 +Subject: Windstream (Demand Notification WMT#: 223456) +Content-Type: text/html; charset=utf-8 +Content-Transfer-Encoding: base64 +Message-Id: <20240806204244.B4EB91800071F@azlapp0432.windstream.com> +MIME-Version: 1.0 + +CjxodG1sPjxoZWFkPg0KPG1ldGEgaHR0cC1lcXVpdj0iQ29udGVudC1UeXBlIiBjb250ZW50PSJ0ZXh0L2h0bWw7IGNoYXJzZXQ9dXRmLTgiPjxzdHlsZT5ib2R5IHtmb250LXNpemU6IDEzcHg7Zm9udC1mYW1pbHk6IEFyaWFsLCBIZWx2ZXRpY2EsIHNhbnMtc2VyaWY7Y29sb3I6ICM0MDQwNDA7bWFyZ2luOiAwcHg7cGFkZGluZzogMDt0ZXh0LWFsaWduOiBsZWZ0O2JhY2tncm91bmQtY29sb3I6ICNmZmY7bWFyZ2luOiAxMHB4IDVweCAxMHB4IDVweDt9LmhlYWRlclJvdyB7YmFja2dyb3VuZDogI0UxRjNDODtmb250LXdlaWdodDogYm9sZDt9LmNpcmN1aXRUYWJsZSB7Ym9yZGVyOiAycHggc29saWQgI0Q1RDVENTtib3JkZXItcmlnaHQ6MHB4O30uY2lyY3VpdFRhYmxlIHRkIHtwYWRkaW5nOjVweDtib3JkZXItcmlnaHQ6MnB4IHNvbGlkICNENUQ1RDU7fS5zdW1tYXJ5IHtwYWRkaW5nOiAwcHggNXB4O30udGJsUGFkZGluZyB7Ym9yZGVyOjJweCBzb2xpZCAjRDVENUQ1O2JvcmRlci1yaWdodDowcHg7Ym9yZGVyLWJvdHRvbTogMHB4O30udGJsUGFkZGluZyB0ZCB7cGFkZGluZzogNXB4O2JvcmRlcjoycHggc29saWQgI0Q1RDVENTtib3JkZXItdG9wOjBweDtib3JkZXItbGVmdDowcHg7fS5ib3R0b21Cb3JkZXIgdGR7Ym9yZGVyLWJvdHRvbToycHggc29saWQgI0Q1RDVENTt9LmFsdENvbG9yIHtiYWNrZ3JvdW5kOiAjRjBGMEYwO31oMSB7Zm9udC1zaXplOjIycHg7dGV4dC1hbGlnbjpjZW50ZXI7fWgyIHtmb250LXNpemU6MTRweDttYXJnaW4tYm90dG9tOjVweDttYXJnaW4tbGVmdDo1cHh9LmRlc2NyaXB0aW9uIHtwYWRkaW5nLWxlZnQ6N3B4O30udGltZVpvbmVUYWJsZSB7Ym9yZGVyOjFweCBzb2xpZCAjMDAwMDAwOyBib3JkZXItYm90dG9tOiAwcHg7IGZvbnQtc2l6ZTogMTJweDsgZm9udC1mYW1pbHk6IENhbGlicmksIEFyaWFsLCBIZWx2ZXRpY2EsIHNhbnMtc2VyaWY7fS50aW1lWm9uZVRhYmxlIHRkIHtib3JkZXItYm90dG9tOjFweCBzb2xpZCAjMDAwMDAwOyBwYWRkaW5nLWxlZnQ6IDEycHg7IHBhZGRpbmctcmlnaHQ6IDEycHg7IHBhZGRpbmctdG9wOiA1cHg7fTwvc3R5bGU+PC9oZWFkPjxib2R5PjxwIGFsaWduPSJjZW50ZXIiIHN0eWxlPSJ0ZXh0LWFsaWduOmNlbnRlciI+PGltZyB3aWR0aD0iMjAwIiBoZWlnaHQ9IjY3IiBzcmM9Imh0dHBzOi8vd2UtdWF0YS53aW5kc3RyZWFtLmNvbS9jZG4yL3dpbl9tb3BfbG9nby5wbmciPjxoMT5EZW1hbmQgTWFpbnRlbmFuY2UgTm90aWZpY2F0aW9uPC9oMT48L3A+PGRpdiBjbGFzcz0ic3VtbWFyeSI+PGJyPldpbmRzdHJlYW0gaGFzIGlkZW50aWZpZWQgYSBuZXR3b3JrIGZhdWx0IGFuZCBtdXN0IHBlcmZvcm0gZGVtYW5kIG1haW50ZW5hbmNlIGluIG9yZGVyIHRvIHJlc3RvcmUgb3VyIG5ldHdvcmsgc2VydmljZXMgdG8gdGhlaXIgZnVsbCBjYXBhYmlsaXRpZXMuIFRoaXMgbWFpbnRlbmFuY2UgaXMgcmVxdWlyZWQgdG8gcmVzb2x2ZSBjdXJyZW50IHNlcnZpY2UgaW1wYWN0cyBvciByZW1vdmUgdGhlIHJpc2sgZm9yIHBvdGVudGlhbCBpbXBhY3RzLiBXZSB1bmRlcnN0YW5kIHRoZSBjaGFsbGVuZ2VzIHRoaXMgbWF5IHByZXNlbnQgYW5kIGFyZSB3b3JraW5nIHRvIG1pbmltaXplIGRpc3J1cHRpb25zLiBUaGUgZGV0YWlscyBvZiB0aGUgcGxhbm5lZCBtYWludGVuYW5jZSBhcmUgbGlzdGVkIGJlbG93IGFsb25nIHdpdGggZGVzY3JpcHRpb25zIGFuZCBwbGFubmVkIGltcGFjdCB0aW1lZnJhbWVzLjxicj48YnI+PGgyPkRFU0NSSVBUSU9OIE9GIE1BSU5URU5BTkNFPC9oMj48c3BhbiBjbGFzcz0iZGVzY3JpcHRpb24iPkZpYmVyIE1haW50ZW5hbmNlIC0gQ2FibGUgUmVsb2NhdGU8YnI+PGJyPjxiPkdQUyBMb2NhdGlvbihzKTogPC9iPjx0YWJsZT48dGhlYWQ+PHRyPjx0aD5MYXRpdHVkZSwgTG9uZ2l0dWRlPC90aD48L3RyPjwvdGhlYWQ+PHRib2R5Pjx0cj48dGQ+MDAuNDc5ODU0LCAtOTkuMzQ0NzExPC90ZD48L3RyPjwvdGJvZHk+PC90YWJsZT48L3NwYW4+PGJyPjxicj48aDI+TUFJTlRFTkFOQ0UgSU5GT1JNQVRJT048L2gyPjx0YWJsZSBib3JkZXI9IjAiIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCI+PHRyPjx0ZCB2YWxpZ249InRvcCI+PHRhYmxlIGJvcmRlcj0iMCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiBjbGFzcz0idGJsUGFkZGluZyI+PHRyPjx0ZD48Yj5XTVQ6PC9iPjwvdGQ+PHRkPjIyMzQ1NjwvdGQ+PC90cj48dHI+PHRkPjxiPk1haW50ZW5hbmNlIEFkZHJlc3M6PC9iPjwvdGQ+PHRkPjxkaXY+U1RSRUVUIEFERFJFU1M8L2Rpdj48L3RkPjwvdHI+PHRyPjx0ZD48Yj5TZXJ2aWNlIEFmZmVjdGluZzo8L2I+PC90ZD48dGQ+WUVTPC90ZD48L3RyPjx0cj48dGQ+PGI+RXZlbnQgU3RhcnQgRGF0ZSAmYW1wOyBUaW1lOjwvYj48L3RkPjx0ZD4wOC8xMy8yNCAwMTowMCBFVDwvdGQ+PC90cj48dHI+PHRkPjxiPkV2ZW50IEVuZCBEYXRlICZhbXA7IFRpbWU6PC9iPjwvdGQ+PHRkPjA4LzEzLzI0IDA5OjAwIEVUPC90ZD48L3RyPjwvdGFibGU+PC90ZD48dGQgdmFsaWduPSJ0b3AiIHN0eWxlPSJwYWRkaW5nLWxlZnQ6MTVweDsiPjx0YWJsZSBib3JkZXI9IjAiIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIgY2xhc3M9InRibFBhZGRpbmciPjx0cj48dGQ+PGI+SW1wYWN0IFR5cGU6PC9iPjwvdGQ+PHRkPjxiPkR1cmF0aW9uPC9iPjwvdGQ+PHRkPjxiPkltcGFjdCBTdGFydDwvYj48L3RkPjx0ZD48Yj5JbXBhY3QgRW5kPC9iPjwvdGQ+PC90cj48dHI+PHRkPk91dGFnZTwvdGQ+PHRkPjQ4MCBtaW51dGUocyk8L3RkPjx0ZD4wOC8xMy8yNCAwMTowMCBFVDwvdGQ+PHRkPjA4LzEzLzI0IDA5OjAwIEVUPC90ZD48L3RyPjx0cj48dGQgY29sc3Bhbj0iNCI+PGVtIHN0eWxlPSJmb250LXNpemU6MTFwdCI+Tm90ZTogU2VydmljZSBpbXBhY3QgbWF5IGJlIGV4cGVyaWVuY2VkIGF0IHZhcnlpbmcgdGltZXMgdGhyb3VnaG91dCB0aGUgaW1wbGVtZW50YXRpb24gd2luZG93LjwvZW0+PC90cj48L3RhYmxlPjwvdGQ+PC90cj48L3RhYmxlPjxicj48YnI+PGgyPjwvaDI+PHRhYmxlIGJvcmRlcj0iMCIgY2VsbHBhZGRpbmc9IjAiIGNlbGxzcGFjaW5nPSIwIiBjbGFzcz0iY2lyY3VpdFRhYmxlIj48dHIgY2xhc3M9ImhlYWRlclJvdyBib3R0b21Cb3JkZXIiPjx0ZD5OYW1lPC90ZD48dGQ+QWNjb3VudDwvdGQ+PHRkPkNpcmN1aXQgSUQ8L3RkPjx0ZD5SYXRlIENvZGU8L3RkPjx0ZD5DdXN0IENrdCBJRDwvdGQ+PHRkPkEtTG9jPC90ZD48dGQ+QS1Mb2MgQWRkcmVzczwvdGQ+PHRkPlotTG9jPC90ZD48dGQ+Wi1Mb2MgQWRkcmVzczwvdGQ+PC90cj48dHI+PHRkPkFjY291bnQgTmFtZTwvdGQ+PHRkPioqKioqMTIzNDwvdGQ+PHRkPldTL0FCQ0QvMTIzNDU2LyAgIC9XWE4gLzwvdGQ+PHRkPlJQUi0wMDwvdGQ+PHRkPjEyMzQ1Njc4PC90ZD48dGQ+QUJDREVPMTI8L3RkPjx0ZD4xMjNUSCBTVDwvdGQ+PHRkPkFCQ0RFRkc8L3RkPjx0ZD4xMjMgRmFrZSBTdHJlZXQ8L3RkPjwvdHI+PC90YWJsZT48YnI+PGJyPklmIHlvdSBleHBlcmllbmNlIGFueSB0cm91YmxlIHdpdGggeW91ciBzZXJ2aWNlIHByaW9yIHRvIG9yIGFmdGVyIHRoaXMgbWFpbnRlbmFuY2Ugd2luZG93IHRpbWUgZnJhbWUgc2hvd24gaW4gdGhpcyBub3RpZmljYXRpb24sIHBsZWFzZSBjb250YWN0IHRoZSBhcHByb3ByaWF0ZSBTZXJ2aWNlIEFzc3VyYW5jZSBncm91cC48YnI+PHVsPjxsaT48Yj5FbnRlcnByaXNlPC9iPjogODAwLTYwMC01MDUwPC9saT48bGk+PGI+V2hvbGVzYWxlPC9iPjogODQ0LTk0Ni0yNjYyPC9saT48bGk+PGI+RmliZXIgVG8gVGhlIFRvd2VyPC9iPjogODc3LTQ3My04MDQyPC9saT48L3VsPjxicj5JZiB5b3UgaGF2ZSBxdWVzdGlvbnMgcGVydGFpbmluZyB0byBvciBpbiByZWZlcmVuY2UgdG8gdGhpcyBtYWludGVuYW5jZSwgcGxlYXNlIGNvbnRhY3QgdGhlIFdpbmRzdHJlYW0gQ2hhbmdlIE1hbmFnZW1lbnQgVGVhbSB2aWEgZW1haWwgZGlyZWN0bHkgYXQgd2NpLm1haW50ZW5hbmNlLm5vdGlmaWNhdGlvbnNAd2luZHN0cmVhbS5jb20gb3IgYnkgY2FsbGluZyB1cyBhdCA4MDAtODkyLTY3ODUuPGJyPjxicj5UaGFuayB5b3UgZm9yIHlvdXIgYnVzaW5lc3MhPC9kaXY+PC9ib2R5PjwvaHRtbD4= diff --git a/tests/unit/data/windstream/windstream2_result.json b/tests/unit/data/windstream/windstream2_result.json new file mode 100644 index 00000000..4bbf3422 --- /dev/null +++ b/tests/unit/data/windstream/windstream2_result.json @@ -0,0 +1,19 @@ +[ + { + "account": "Account Name", + "circuits": [ + { + "circuit_id": "WS/ABCD/123456/ /WXN /", + "impact": "OUTAGE" + } + ], + "end": 1723554000, + "maintenance_id": "223456", + "organizer": "wci.maintenance.notifications@windstream.com", + "provider": "windstream", + "stamp": 1722976963, + "start": 1723525200, + "status": "CONFIRMED", + "summary": "Windstream has identified a network fault and must perform demand maintenance in order to restore our network services to their full capabilities. This maintenance is required to resolve current service impacts or remove the risk for potential impacts. We understand the challenges this may present and are working to minimize disruptions. The details of the planned maintenance are listed below along with descriptions and planned impact timeframes." + } +] \ No newline at end of file diff --git a/tests/unit/test_e2e.py b/tests/unit/test_e2e.py index 674c79b5..b578173f 100644 --- a/tests/unit/test_e2e.py +++ b/tests/unit/test_e2e.py @@ -862,6 +862,13 @@ ], [Path(dir_path, "data", "windstream", "windstream1_result.json")], ), + ( + Windstream, + [ + ("email", Path(dir_path, "data", "windstream", "windstream2.eml")), + ], + [Path(dir_path, "data", "windstream", "windstream2_result.json")], + ), # Zayo ( Zayo,