1
0
mirror of https://github.com/pyro2927/SouthwestCheckin.git synced 2025-12-06 01:13:19 +00:00

Refactoring Southwest class to be OOP

This commit is contained in:
pyro2927
2019-02-16 15:25:43 -08:00
parent 170519d316
commit d7722fa1ce
5 changed files with 83 additions and 71 deletions

View File

@@ -5,4 +5,4 @@ python:
- "3.7.1" - "3.7.1"
script: script:
- pytest - pytest
- pycodestyle checkin.py --show-source --ignore=E501 - pycodestyle *.py --show-source --ignore=E501

View File

@@ -20,17 +20,17 @@ from dateutil.parser import parse
from docopt import docopt from docopt import docopt
from math import trunc from math import trunc
from pytz import utc from pytz import utc
from southwest import Reservation
from threading import Thread from threading import Thread
from tzlocal import get_localzone from tzlocal import get_localzone
import openflights import openflights
import southwest
import sys import sys
import time import time
CHECKIN_EARLY_SECONDS = 5 CHECKIN_EARLY_SECONDS = 5
def schedule_checkin(flight_time, number, first, last, notify=[]): def schedule_checkin(flight_time, reservation):
checkin_time = flight_time - timedelta(days=1) checkin_time = flight_time - timedelta(days=1)
current_time = datetime.now(utc).astimezone(get_localzone()) current_time = datetime.now(utc).astimezone(get_localzone())
# check to see if we need to sleep until 24 hours before flight # check to see if we need to sleep until 24 hours before flight
@@ -42,16 +42,15 @@ def schedule_checkin(flight_time, number, first, last, notify=[]):
h, m = divmod(m, 60) h, m = divmod(m, 60)
print("Too early to check in. Waiting {} hours, {} minutes, {} seconds".format(trunc(h), trunc(m), s)) print("Too early to check in. Waiting {} hours, {} minutes, {} seconds".format(trunc(h), trunc(m), s))
time.sleep(delta) time.sleep(delta)
data = southwest.checkin(number, first, last) data = reservation.checkin()
for flight in data['flights']: for flight in data['flights']:
for doc in flight['passengers']: for doc in flight['passengers']:
print("{} got {}{}!".format(doc['name'], doc['boardingGroup'], doc['boardingPosition'])) print("{} got {}{}!".format(doc['name'], doc['boardingGroup'], doc['boardingPosition']))
if len(notify) > 0:
southwest.send_notification(data, notify)
def auto_checkin(reservation_number, first_name, last_name, notify=[]): def auto_checkin(reservation_number, first_name, last_name, notify=[]):
body = southwest.lookup_existing_reservation(reservation_number, first_name, last_name) r = Reservation(reservation_number, first_name, last_name, notify)
body = r.lookup_existing_reservation()
# Get our local current time # Get our local current time
now = datetime.now(utc).astimezone(get_localzone()) now = datetime.now(utc).astimezone(get_localzone())
@@ -70,7 +69,7 @@ def auto_checkin(reservation_number, first_name, last_name, notify=[]):
# found a flight for checkin! # found a flight for checkin!
print("Flight information found, departing {} at {}".format(airport, date.strftime('%b %d %I:%M%p'))) print("Flight information found, departing {} at {}".format(airport, date.strftime('%b %d %I:%M%p')))
# Checkin with a thread # Checkin with a thread
t = Thread(target=schedule_checkin, args=(date, reservation_number, first_name, last_name, notify)) t = Thread(target=schedule_checkin, args=(date, r))
t.daemon = True t.daemon = True
t.start() t.start()
threads.append(t) threads.append(t)

View File

@@ -8,6 +8,7 @@ from datetime import datetime, timedelta
from pytz import timezone, utc from pytz import timezone, utc
from tzlocal import get_localzone from tzlocal import get_localzone
def template_time(file_name): def template_time(file_name):
in_string = open(file_name, 'r').read() in_string = open(file_name, 'r').read()
t = datetime.now() + timedelta(seconds=5) t = datetime.now() + timedelta(seconds=5)
@@ -15,6 +16,7 @@ def template_time(file_name):
in_string = in_string.replace('TIME_HERE', t.strftime('%H:%M')) in_string = in_string.replace('TIME_HERE', t.strftime('%H:%M'))
return in_string return in_string
def test_checkin(requests_mock): def test_checkin(requests_mock):
requests_mock.register_uri('GET', '/api/mobile-misc/v1/mobile-misc/page/view-reservation/XXXX?first-name=John&last-name=Smith', text=template_time('fixtures/view-reservation.json')) requests_mock.register_uri('GET', '/api/mobile-misc/v1/mobile-misc/page/view-reservation/XXXX?first-name=John&last-name=Smith', text=template_time('fixtures/view-reservation.json'))
requests_mock.register_uri('GET', '/api/mobile-air-operations/v1/mobile-air-operations/page/check-in/XXXX?first-name=John&last-name=Smith', text=template_time('fixtures/checkin-get.json')) requests_mock.register_uri('GET', '/api/mobile-air-operations/v1/mobile-air-operations/page/check-in/XXXX?first-name=John&last-name=Smith', text=template_time('fixtures/checkin-get.json'))
@@ -22,14 +24,16 @@ def test_checkin(requests_mock):
requests_mock.register_uri('POST', '/php/apsearch.php', text=template_time('fixtures/openflights.json')) requests_mock.register_uri('POST', '/php/apsearch.php', text=template_time('fixtures/openflights.json'))
try: try:
checkin.auto_checkin('XXXX', 'John', 'Smith') checkin.auto_checkin('XXXX', 'John', 'Smith')
except: except Exception:
pytest.fail("Error checking in") pytest.fail("Error checking in")
def test_timezone_localization(): def test_timezone_localization():
tz = timezone('America/Los_Angeles') tz = timezone('America/Los_Angeles')
date = tz.localize(datetime.strptime('2018-01-01 13:00', '%Y-%m-%d %H:%M')) date = tz.localize(datetime.strptime('2018-01-01 13:00', '%Y-%m-%d %H:%M'))
assert date.strftime('%z') == '-0800' assert date.strftime('%z') == '-0800'
@vcr.use_cassette() @vcr.use_cassette()
def test_openflights_api(): def test_openflights_api():
tzrequest = {'iata': 'LAX', tzrequest = {'iata': 'LAX',
@@ -42,24 +46,22 @@ def test_openflights_api():
airport_tz = timezone(json.loads(tzresult.text)['airports'][0]['tz_id']) airport_tz = timezone(json.loads(tzresult.text)['airports'][0]['tz_id'])
assert airport_tz.zone == "America/Los_Angeles" assert airport_tz.zone == "America/Los_Angeles"
def test_notifications(requests_mock, mocker): def test_notifications(requests_mock, mocker):
requests_mock.register_uri('GET', '/api/mobile-air-operations/v1/mobile-air-operations/page/check-in/XXXX?first-name=John&last-name=Smith', text=template_time('fixtures/checkin-get.json')) requests_mock.register_uri('GET', '/api/mobile-air-operations/v1/mobile-air-operations/page/check-in/XXXX?first-name=John&last-name=Smith', text=template_time('fixtures/checkin-get.json'))
data = template_time('fixtures/checkin-post.json') data = template_time('fixtures/checkin-post.json')
requests_mock.register_uri('POST', '/api/mobile-air-operations/v1/mobile-air-operations/page/check-in', text=data) requests_mock.register_uri('POST', '/api/mobile-air-operations/v1/mobile-air-operations/page/check-in', text=data)
data = json.loads(data) data = json.loads(data)
requests_mock.register_uri('POST', '/php/apsearch.php', text=template_time('fixtures/openflights.json')) requests_mock.register_uri('POST', '/php/apsearch.php', text=template_time('fixtures/openflights.json'))
mocked_checkin = mocker.patch('southwest.send_notification') mocked_checkin = mocker.patch('southwest.Reservation.send_notification')
t = datetime.now(utc).astimezone(get_localzone()) + timedelta(minutes=5) t = datetime.now(utc).astimezone(get_localzone()) + timedelta(minutes=5)
try: try:
checkin.schedule_checkin(t, 'XXXX', 'John', 'Smith') r = southwest.Reservation('XXXX', 'John', 'Smith')
southwest.send_notification.assert_not_called() checkin.schedule_checkin(t, r)
email = [{'mediaType': 'EMAIL', 'emailAddress': 'test@example.com'}] mocked_checkin.assert_not_called()
checkin.schedule_checkin(t, 'XXXX', 'John', 'Smith', email) r.notifications = [{'mediaType': 'EMAIL', 'emailAddress': 'test@example.com'}]
southwest.send_notification.assert_called_once_with(data['checkInConfirmationPage'], email) checkin.schedule_checkin(t, r)
southwest.send_notification.reset_mock() mocked_checkin.assert_called_once()
phone = [{'mediaType': 'SMS', 'phoneNumber': '1234567890'}] except Exception:
checkin.schedule_checkin(t, 'XXXX', 'John', 'Smith', phone)
southwest.send_notification.assert_called_once_with(data['checkInConfirmationPage'], phone)
except:
pytest.fail("Error checking in") pytest.fail("Error checking in")

View File

@@ -2,6 +2,7 @@ import requests
import json import json
import pytz import pytz
def timezone_for_airport(airport_code): def timezone_for_airport(airport_code):
tzrequest = {'iata': airport_code, tzrequest = {'iata': airport_code,
'country': 'ALL', 'country': 'ALL',

View File

@@ -10,10 +10,19 @@ MAX_ATTEMPTS = 40
# Pulled from proxying the Southwest iOS App # Pulled from proxying the Southwest iOS App
headers = {'Host': 'mobile.southwest.com', 'Content-Type': 'application/json', 'X-API-Key': API_KEY, 'X-User-Experience-Id': USER_EXPERIENCE_KEY, 'Accept': '*/*'} headers = {'Host': 'mobile.southwest.com', 'Content-Type': 'application/json', 'X-API-Key': API_KEY, 'X-User-Experience-Id': USER_EXPERIENCE_KEY, 'Accept': '*/*'}
class Reservation():
def __init__(self, number, first, last, notifications=[]):
self.number = number
self.first = first
self.last = last
self.notifications = []
# You might ask yourself, "Why the hell does this exist?" # You might ask yourself, "Why the hell does this exist?"
# Basically, there sometimes appears a "hiccup" in Southwest where things # Basically, there sometimes appears a "hiccup" in Southwest where things
# aren't exactly available 24-hours before, so we try a few times # aren't exactly available 24-hours before, so we try a few times
def safe_request(url, body=None): def safe_request(self, url, body=None):
try: try:
attempts = 0 attempts = 0
while True: while True:
@@ -34,34 +43,35 @@ def safe_request(url, body=None):
# Ignore responses with no json data in body # Ignore responses with no json data in body
pass pass
def lookup_existing_reservation(number, first, last): def lookup_existing_reservation(self):
# Find our existing record # Find our existing record
url = "{}mobile-misc/v1/mobile-misc/page/view-reservation/{}?first-name={}&last-name={}".format(BASE_URL, number, first, last) url = "{}mobile-misc/v1/mobile-misc/page/view-reservation/{}?first-name={}&last-name={}".format(BASE_URL, self.number, self.first, self.last)
data = safe_request(url) data = self.safe_request(url)
return data['viewReservationViewPage'] return data['viewReservationViewPage']
def get_checkin_data(number, first, last): def get_checkin_data(self):
url = "{}mobile-air-operations/v1/mobile-air-operations/page/check-in/{}?first-name={}&last-name={}".format(BASE_URL, number, first, last) url = "{}mobile-air-operations/v1/mobile-air-operations/page/check-in/{}?first-name={}&last-name={}".format(BASE_URL, self.number, self.first, self.last)
data = safe_request(url) data = self.safe_request(url)
return data['checkInViewReservationPage'] return data['checkInViewReservationPage']
def checkin(number, first, last): def checkin(self):
data = get_checkin_data(number, first, last) data = self.get_checkin_data()
info_needed = data['_links']['checkIn'] info_needed = data['_links']['checkIn']
url = "{}mobile-air-operations{}".format(BASE_URL, info_needed['href']) url = "{}mobile-air-operations{}".format(BASE_URL, info_needed['href'])
print("Attempting check-in...") print("Attempting check-in...")
return safe_request(url, info_needed['body'])['checkInConfirmationPage'] confirmation = self.safe_request(url, info_needed['body'])['checkInConfirmationPage']
if len(self.notifications) > 0:
self.send_notification(confirmation)
return confirmation
def send_notification(checkindata, notify): def send_notification(self, checkindata):
if len(notify) < 1:
return
info_needed = checkindata['_links']['boardingPasses'] info_needed = checkindata['_links']['boardingPasses']
url = "{}mobile-air-operations{}".format(BASE_URL, info_needed['href']) url = "{}mobile-air-operations{}".format(BASE_URL, info_needed['href'])
mbpdata = safe_request(url, info_needed['body']) mbpdata = self.safe_request(url, info_needed['body'])
info_needed = mbpdata['checkInViewBoardingPassPage']['_links'] info_needed = mbpdata['checkInViewBoardingPassPage']['_links']
url = "{}mobile-air-operations{}".format(BASE_URL, info_needed['href']) url = "{}mobile-air-operations{}".format(BASE_URL, info_needed['href'])
print("Attempting to send boarding pass...") print("Attempting to send boarding pass...")
body = info_needed['body'] body = info_needed['body']
for n in notify: for n in self.notifications:
body.update(n) body.update(n)
safe_request(url, body) self.safe_request(url, body)