From 22c0ef797ca95e783f7ab750b2250d7b5a9ab48c Mon Sep 17 00:00:00 2001 From: pyro2927 Date: Sun, 17 Feb 2019 23:29:40 -0800 Subject: [PATCH] Refactoring notifications --- southwest/__init__.py | 2 + southwest/notifications.py | 8 ++ tests/checkin_test.py | 27 ++++--- tests/fixtures/cassettes/test_checkin.yml | 12 +-- .../cassettes/test_openflights_api.yml | 4 +- .../cassettes/test_reservation_lookup.yml | 74 +++++++++++++++++++ tests/my_vcr.py | 20 +++-- 7 files changed, 122 insertions(+), 25 deletions(-) create mode 100644 southwest/notifications.py create mode 100644 tests/fixtures/cassettes/test_reservation_lookup.yml diff --git a/southwest/__init__.py b/southwest/__init__.py index 0c0a0a4..48c6a41 100644 --- a/southwest/__init__.py +++ b/southwest/__init__.py @@ -1 +1,3 @@ +from .notifications import Notifications from .southwest import Reservation +from .openflights import timezone_for_airport diff --git a/southwest/notifications.py b/southwest/notifications.py new file mode 100644 index 0000000..4cf65cd --- /dev/null +++ b/southwest/notifications.py @@ -0,0 +1,8 @@ +class Notifications: + @staticmethod + def Phone(number): + return {'mediaType': 'SMS', 'phoneNumber': number} + + @staticmethod + def Email(email_address): + return {'mediaType': 'EMAIL', 'emailAddress': email_address} diff --git a/tests/checkin_test.py b/tests/checkin_test.py index e7939c3..694a04d 100644 --- a/tests/checkin_test.py +++ b/tests/checkin_test.py @@ -8,25 +8,32 @@ from pytz import timezone, utc from tzlocal import get_localzone my_vcr = custom_vcr() +r = southwest.Reservation('XXXXXX', 'John', 'Smith') + +@my_vcr.use_cassette() +def test_reservation_lookup(): + print(r.notifications) + try: + r.lookup_existing_reservation() + except Exception: + pytest.fail("Error looking up reservation") @my_vcr.use_cassette() def test_checkin(): - r = southwest.Reservation('XXXXXX', 'John', 'Smith') try: r.checkin() except Exception: pytest.fail("Error checking in") +def test_notifications(): + phone = southwest.Notifications.Phone('1234567890') + email = southwest.Notifications.Email('test@example.com') + r.notifications = [phone, email] + #TODO: test firing these off + + @my_vcr.use_cassette() def test_openflights_api(): - tzrequest = {'iata': 'LAX', - 'country': 'ALL', - 'db': 'airports', - 'iatafilter': 'true', - 'action': 'SEARCH', - 'offset': '0'} - tzresult = requests.post("https://openflights.org/php/apsearch.php", tzrequest) - airport_tz = timezone(json.loads(tzresult.text)['airports'][0]['tz_id']) - assert airport_tz.zone == "America/Los_Angeles" + assert southwest.timezone_for_airport('LAX').zone == "America/Los_Angeles" diff --git a/tests/fixtures/cassettes/test_checkin.yml b/tests/fixtures/cassettes/test_checkin.yml index 8eb70e3..6f7ac11 100644 --- a/tests/fixtures/cassettes/test_checkin.yml +++ b/tests/fixtures/cassettes/test_checkin.yml @@ -46,13 +46,13 @@ interactions: Cache-Control: ['max-age=0, no-cache, no-store'] Connection: [keep-alive] Content-Type: [application/json] - Date: ['Mon, 18 Feb 2019 06:29:03 GMT'] - Expires: ['Mon, 18 Feb 2019 06:29:03 GMT'] + Date: ['Mon, 18 Feb 2019 07:24:48 GMT'] + Expires: ['Mon, 18 Feb 2019 07:24:48 GMT'] Pragma: [no-cache] Server: [Apache-Coyote/1.1] Strict-Transport-Security: [max-age=60] Vary: [Accept-Encoding] - X-Request-ID: [oMM1W3JIQrS_12lpUJIJdg] + X-Request-ID: [QZCIaesZQnuKkmmy37tLrg] X-User-Experience-ID: [AAAA3198-4545-46F4-9A05-BB3E868BEFF5] content-length: ['13088'] status: {code: 200, message: OK} @@ -94,13 +94,13 @@ interactions: Cache-Control: ['max-age=0, no-cache, no-store'] Connection: [keep-alive] Content-Type: [application/json] - Date: ['Mon, 18 Feb 2019 06:29:03 GMT'] - Expires: ['Mon, 18 Feb 2019 06:29:03 GMT'] + Date: ['Mon, 18 Feb 2019 07:24:48 GMT'] + Expires: ['Mon, 18 Feb 2019 07:24:48 GMT'] Pragma: [no-cache] Server: [Apache-Coyote/1.1] Strict-Transport-Security: [max-age=60] Vary: [Accept-Encoding] - X-Request-ID: [-UaFbua-QXu62S3ZInJ-WQ] + X-Request-ID: [YKbshcq_RJ2cCrd0FRsctQ] X-User-Experience-ID: [AAAA3198-4545-46F4-9A05-BB3E868BEFF5] content-length: ['12674'] status: {code: 200, message: OK} diff --git a/tests/fixtures/cassettes/test_openflights_api.yml b/tests/fixtures/cassettes/test_openflights_api.yml index 4e0c9df..6d6bc2d 100644 --- a/tests/fixtures/cassettes/test_openflights_api.yml +++ b/tests/fixtures/cassettes/test_openflights_api.yml @@ -21,12 +21,12 @@ interactions: Cache-Control: ['no-store, no-cache, must-revalidate, post-check=0, pre-check=0'] Connection: [Keep-Alive] Content-Type: [text/html] - Date: ['Mon, 18 Feb 2019 06:29:04 GMT'] + Date: ['Mon, 18 Feb 2019 07:24:50 GMT'] Expires: ['Thu, 19 Nov 1981 08:52:00 GMT'] Keep-Alive: ['timeout=5, max=100'] Pragma: [no-cache] Server: [Apache/2.4.7 (Ubuntu)] - Set-Cookie: [PHPSESSID=covu8plcltmotne4jvc976bk67; path=/] + Set-Cookie: [PHPSESSID=mpoesla4lf9h12d3hnp5fn6t24; path=/] Vary: [Accept-Encoding] X-Powered-By: [PHP/5.5.9-1ubuntu4.26] content-length: ['405'] diff --git a/tests/fixtures/cassettes/test_reservation_lookup.yml b/tests/fixtures/cassettes/test_reservation_lookup.yml new file mode 100644 index 0000000..e1a7953 --- /dev/null +++ b/tests/fixtures/cassettes/test_reservation_lookup.yml @@ -0,0 +1,74 @@ +interactions: +- request: + body: null + headers: + Accept: ['*/*'] + Accept-Encoding: ['gzip, deflate'] + Connection: [keep-alive] + Content-Type: [application/json] + Host: [mobile.southwest.com] + User-Agent: [python-requests/2.21.0] + X-API-Key: [l7xxb3dcccc4a5674bada48fc6fcf0946bc8] + X-User-Experience-Id: [AAAA3198-4545-46F4-9A05-BB3E868BEFF5] + method: GET + uri: https://mobile.southwest.com/api/mobile-misc/v1/mobile-misc/page/view-reservation/XXXXXX + response: + body: {string: '{"viewReservationViewPage": {"dates": {"first": "2019-02-18", + "second": null}, "checkInIneligibilityReason": null, "destinationDescription": + "Los Angeles", "originAirport": {"name": "[REDACTED]", "state": "OR", "code": + "PDX", "country": null}, "destinationAirport": {"name": "[REDACTED]", "state": + "CA", "code": "LAX", "country": null}, "standbyFlight": null, "companion": + null, "passengers": "[REDACTED]", "confirmationNumber": "XXXXXX", "shouldShowAddEarlyBirdButton": + false, "bounds": [{"departureStatus": "ON TIME", "departureStatusType": "POSITIVE", + "arrivalStatus": "ON TIME", "arrivalStatusType": "POSITIVE", "flights": [{"number": + "1614", "wifiOnBoard": true}], "travelTime": "2h 20m", "departureDate": "2019-02-18", + "departureTime": "13:45", "departureAirport": {"name": "[REDACTED]", "state": + "OR", "code": "PDX", "country": null}, "arrivalTime": "16:05", "arrivalAirport": + {"name": "[REDACTED]", "state": "CA", "code": "LAX", "country": null}, "passengerTypeCounts": + {"adult": 1, "senior": 0}, "fareType": "Companion", "boundType": "DEPARTING", + "standbyFlight": null, "stops": [], "isNextDayArrival": false}], "pageHeader": + "PDX - LAX", "shareDetails": {"subject": "Southwest Flight 1614 Portland to + Los Angeles", "confirmationInfo": "Confirmation #: XXXXXX", "passengerInfo": + "[REDACTED]", "flightInfo": [{"header": "Departing Flight: Mon, Feb 18, 2019", + "flightInfo": "Flight #: 1614", "departureInfo": "Departs: 01:45 PM PDX", + "stops": null, "arrivalInfo": "Arrives: 04:05 PM LAX", "travelTime": "Travel + time: 2hr 20 mins"}]}, "hasAnyCancelledFlights": false, "isCheckInEligible": + true, "isCheckedIn": true, "isInternational": false, "isDynamicWaiver": false, + "isNonRevPnr": false, "_v1_infoNeededToChange": {"href": "/v1/mobile/reservations/record-locator/XXXXXX", + "method": "GET", "query": {"action": "CHANGE", "first-name": "[REDACTED]", + "last-name": "[REDACTED]"}}, "_v1_infoNeededToCancel": {"href": "/v1/mobile/reservations/record-locator/XXXXXX", + "method": "GET", "query": {"action": "CANCEL", "first-name": "[REDACTED]", + "last-name": "[REDACTED]"}}, "_v1_infoNeededToAddCompanion": null, "_links": + {"checkInSessionToken": "[REDACTED]", "earlyBird": null, "change": {"href": + "/v1/mobile-air-booking/page/flights/change/current/XXXXXX", "method": "GET", + "query": {"first-name": "[REDACTED]", "last-name": "[REDACTED]"}}, "cancel": + {"href": "/v1/mobile-air-booking/page/cancel-reservation/XXXXXX", "method": + "GET", "query": {"first-name": "[REDACTED]", "last-name": "[REDACTED]"}}, + "viewStandbyList": null, "checkIn": null, "viewBoardingPass": {"href": "/v1/mobile-air-operations/page/check-in/view-boarding-pass", + "method": "POST", "body": {"firstName": "[REDACTED]", "lastName": "[REDACTED]", + "recordLocator": "[REDACTED]"}}, "viewBoardingPositions": null, "addCompanion": + null, "passportEmergencyContacts": null}, "hasUnaccompaniedMinor": false}}'} + headers: + Access-Control-Allow-Credentials: ['true'] + Access-Control-Allow-Headers: ['origin, content-type, accept, authorization, + token, User-Agent, X-Forwarded-For, X-User-Experience-ID, X-Request-ID, + X-API-Key, X-Account-Number, X-Swa-Region, X-Channel-Id, X-Api-IDToken, + true-host'] + Access-Control-Allow-Methods: ['GET, POST, PUT, DELETE, OPTIONS, HEAD'] + Access-Control-Allow-Origin: [''] + Access-Control-Expose-Headers: ['X-User-Experience-ID, X-Request-ID'] + Access-Control-Max-Age: ['1'] + Cache-Control: ['max-age=0, no-cache, no-store'] + Connection: [keep-alive] + Content-Type: [application/json] + Date: ['Mon, 18 Feb 2019 07:24:47 GMT'] + Expires: ['Mon, 18 Feb 2019 07:24:47 GMT'] + Pragma: [no-cache] + Server: [Apache-Coyote/1.1] + Strict-Transport-Security: [max-age=60] + Vary: [Accept-Encoding] + X-Request-ID: [6JM3yBL0QIahYeZtLYc8QA] + X-User-Experience-ID: [AAAA3198-4545-46F4-9A05-BB3E868BEFF5] + content-length: ['8422'] + status: {code: 200, message: OK} +version: 1 diff --git a/tests/my_vcr.py b/tests/my_vcr.py index 3746729..3953dc7 100644 --- a/tests/my_vcr.py +++ b/tests/my_vcr.py @@ -4,18 +4,21 @@ import os # remove sensitive values from JSON response bad_fields = [ - 'recordLocator', 'checkInSessionToken', - 'name', - 'firstName', - 'lastName', - 'passengers', 'first-name', - 'last-name' + 'firstName', + 'last-name', + 'lastName', + 'name', + 'passengerInfo', + 'passengers', + 'recordLocator' ] def redact(obj): + if isinstance(obj, str): + return for k, v in list(obj.items()): if k in bad_fields: obj[k] = '[REDACTED]' @@ -27,7 +30,10 @@ def redact(obj): def filter_payload(response): - string_body = response['body']['string'].decode('utf8') + s = response['body']['string'] + if len(s) == 0: + return response + string_body = s.decode('utf8') body = json.loads(string_body) redact(body) response['body']['string'] = json.dumps(body).encode()