add script for adding reservation comment
This commit is contained in:
parent
612ab8e975
commit
0b9e81380c
199
make_reservations.py
Normal file
199
make_reservations.py
Normal file
@ -0,0 +1,199 @@
|
||||
from selenium import webdriver
|
||||
from selenium.webdriver.remote import webelement
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
from selenium.common.exceptions import TimeoutException
|
||||
from selenium.webdriver.support import expected_conditions as EC
|
||||
from selenium.webdriver.common.by import By
|
||||
from selenium.webdriver.firefox.service import Service as FirefoxService
|
||||
from selenium.webdriver.firefox.firefox_profile import FirefoxProfile
|
||||
from webdriver_manager.firefox import GeckoDriverManager
|
||||
import configparser
|
||||
import os
|
||||
import sys
|
||||
import datetime
|
||||
import argparse
|
||||
|
||||
# TODO factor out common code (defaults, login, etc) from progress_reports script
|
||||
GECKO_DRIVER = 'gecko'
|
||||
CHROME_DRIVER = 'chrome'
|
||||
DEFAULT_CONFIG_PATH = './config.ini'
|
||||
|
||||
DEFAULT_WORKING_DIRECTORY = './tmp'
|
||||
DEFAULT_APP_URL = 'https://app.flightschedulepro.com'
|
||||
DEFAULT_TIMEOUT = 10 # seconds
|
||||
DEFAULT_DAY_LOOKAHEAD = 2
|
||||
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
prog='FSP Make Reservations',
|
||||
description='Reserves flights in advance',
|
||||
epilog='Kill urself')
|
||||
parser.add_argument('-c', '--config', default=DEFAULT_CONFIG_PATH)
|
||||
parser.add_argument('-s', '--show_browser', help='Show browser window', action='store_true')
|
||||
parser.add_argument('-d', '--days', help='Number of days in advance to place reservations for', default=DEFAULT_DAY_LOOKAHEAD)
|
||||
parser.add_argument('-D', '--dry_run', help='Disables saving of comments', action='store_true')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
config = configparser.ConfigParser()
|
||||
|
||||
config.read(args.config)
|
||||
working_dir = config['main'].get('working_directory', DEFAULT_WORKING_DIRECTORY)
|
||||
app_url = config['main'].get('app_url', DEFAULT_APP_URL)
|
||||
timeout = config['main'].get('timeout', DEFAULT_TIMEOUT)
|
||||
tenant_id = config['main'].get('tenant_id')
|
||||
if tenant_id is None or tenant_id == "":
|
||||
print('No Tenant ID configured!')
|
||||
sys.exit(1)
|
||||
|
||||
# HACK maybe Ubuntu specific
|
||||
if config['main'].getboolean('use_working_dir_for_tmp', False):
|
||||
os.environ["TMPDIR"] = working_dir
|
||||
|
||||
|
||||
driver_type = config['main']['driver']
|
||||
# TODO only firefox for now
|
||||
if driver_type == GECKO_DRIVER:
|
||||
opt = webdriver.FirefoxOptions()
|
||||
if config['firefox'].get('binary_path') is not None:
|
||||
opt.binary_location = config['firefox'].get('binary_path')
|
||||
if not args.show_browser:
|
||||
opt.add_argument('-headless')
|
||||
# Force window size to avoid issues with responsive design
|
||||
opt.add_argument("--width=1920")
|
||||
opt.add_argument("--height=1080")
|
||||
# Disable print dialog. Causes race conditions with window switching
|
||||
firefox_profile = FirefoxProfile()
|
||||
firefox_profile.set_preference("print.enabled", False)
|
||||
opt.profile = firefox_profile
|
||||
driver = webdriver.Firefox(options=opt, service=FirefoxService(GeckoDriverManager().install()))
|
||||
else:
|
||||
print(f'unsupported driver type "{driver_type}"')
|
||||
sys.exit(1)
|
||||
|
||||
# optionally prints a message and cleans up before exiting
|
||||
def die(message=None):
|
||||
if message is not None:
|
||||
print(message)
|
||||
driver.quit()
|
||||
sys.exit(0)
|
||||
|
||||
login_url = app_url + '/Account/Login?company='+ tenant_id
|
||||
driver.get(login_url)
|
||||
|
||||
# wait for stupid cookie modal to load and accept all ¯\_(ツ)_/¯
|
||||
try:
|
||||
WebDriverWait(driver, timeout).until(
|
||||
EC.presence_of_all_elements_located((By.ID, 'onetrust-accept-btn-handler'))
|
||||
)
|
||||
cookie_btn = driver.find_element(By.ID, 'onetrust-accept-btn-handler')
|
||||
cookie_btn.click()
|
||||
except:
|
||||
pass
|
||||
|
||||
# Login
|
||||
form = driver.find_element(By.CLASS_NAME, 'account-form')
|
||||
username = driver.find_element(By.ID, 'username')
|
||||
username.send_keys(config['main']['username'])
|
||||
username.submit()
|
||||
|
||||
try:
|
||||
WebDriverWait(driver, timeout).until(
|
||||
EC.presence_of_all_elements_located((By.ID, 'password'))
|
||||
)
|
||||
except TimeoutException:
|
||||
if len(driver.find_elements(By.XPATH, '//div[@id="alerts"]')) > 0:
|
||||
die('Bad username')
|
||||
die('unknown authentication error')
|
||||
|
||||
password = driver.find_element(By.ID, 'password')
|
||||
password.send_keys(config['main']['password'])
|
||||
|
||||
password.submit()
|
||||
|
||||
# Wait for app to load and naviagte to Reservations "page"
|
||||
try:
|
||||
WebDriverWait(driver, timeout).until(
|
||||
EC.presence_of_all_elements_located((By.CLASS_NAME, 'fsp-main-drawer-content'))
|
||||
)
|
||||
except TimeoutException:
|
||||
if len(driver.find_elements(By.XPATH, '//div[@id="alerts"]')) > 0:
|
||||
die('Bad password')
|
||||
die('unknown authentication error')
|
||||
|
||||
today = datetime.datetime.today()
|
||||
def get_reservation_rows():
|
||||
driver.get(app_url + '/App/Reservations')
|
||||
# Wait for "Future" button and click
|
||||
WebDriverWait(driver, timeout).until(
|
||||
EC.presence_of_all_elements_located((By.XPATH, '//a[@id="mat-tab-link-1"]'))
|
||||
)
|
||||
driver.find_element(By.XPATH, '//a[@id="mat-tab-link-1"]').click()
|
||||
|
||||
#Wait for rows to load
|
||||
WebDriverWait(driver, timeout).until(
|
||||
EC.presence_of_all_elements_located((By.XPATH, '//tr[contains(@class, "cdk-row")]'))
|
||||
)
|
||||
reservation_rows = driver.find_elements(By.XPATH, '//tr[contains(@class, "cdk-row")]')
|
||||
|
||||
reservation_rows = list(filter(filter_row_by_date, reservation_rows))
|
||||
return reservation_rows
|
||||
|
||||
def filter_row_by_date(reservation_row: webelement.WebElement) -> bool:
|
||||
instructor = reservation_row.find_element(By.XPATH, './td[contains(@class, "cdk-column-instructor")]').get_attribute("innerText")
|
||||
# Double check we're only commenting on your reservations. Out of caution abort if we see any other instructors
|
||||
if "Jason Vitale" not in instructor:
|
||||
die("WARNING: retrieved reservation for another instructor. Aborting...")
|
||||
return False
|
||||
date_str = reservation_row.find_element(By.XPATH, './td[contains(@class, "cdk-column-date")]').get_attribute("innerText")
|
||||
date = datetime.datetime.strptime(date_str, '%a, %b %d, %Y')
|
||||
if date.date() == (today + datetime.timedelta(days=args.days)).date():
|
||||
return True
|
||||
return False
|
||||
|
||||
rows = get_reservation_rows()
|
||||
|
||||
print('found ' + str(len(rows)) + ' reservations to add reservation comment to')
|
||||
for i in range(0, len(rows)):
|
||||
row = rows[i]
|
||||
row.find_element(By.XPATH, './/button[contains(@class, "fsp-button")]').click()
|
||||
|
||||
WebDriverWait(driver, timeout).until(
|
||||
EC.presence_of_all_elements_located((By.ID, 'ReservationModal-StandardViewCtrl')),
|
||||
)
|
||||
modal = driver.find_element(By.ID, 'ReservationModal-StandardViewCtrl')
|
||||
#Wait for modal/comments sections to load
|
||||
WebDriverWait(driver, timeout).until(
|
||||
EC.presence_of_all_elements_located((By.XPATH, '//div[contains(@ng-model, "reservationDetails.comments")]')),
|
||||
)
|
||||
WebDriverWait(driver, timeout).until(
|
||||
EC.presence_of_all_elements_located((By.XPATH, '//a[contains(@ng-click, "editComment()")]')),
|
||||
)
|
||||
|
||||
comments = modal.find_element(By.XPATH, './/div[contains(@ng-model, "reservationDetails.comments")]')
|
||||
edit_btn = comments.find_element(By.XPATH, './/a[contains(@ng-click, "editComment()")]')
|
||||
WebDriverWait(driver, timeout).until(
|
||||
EC.element_to_be_clickable(edit_btn)
|
||||
)
|
||||
edit_btn.click()
|
||||
#Wait for modal/comments sections to load
|
||||
WebDriverWait(driver, timeout).until(
|
||||
EC.presence_of_all_elements_located((By.ID, 'comments'))
|
||||
)
|
||||
textarea = comments.find_element(By.ID, 'comments')
|
||||
|
||||
textarea.clear()
|
||||
textarea.send_keys("c172 " + today.strftime('%d %b, %H:%S'))
|
||||
|
||||
if args.dry_run is False:
|
||||
save_btn = comments.find_element(By.XPATH, './/button[contains(@ng-click, "save()")]')
|
||||
WebDriverWait(driver, timeout).until(
|
||||
EC.element_to_be_clickable(save_btn)
|
||||
)
|
||||
print("saving reservation comment")
|
||||
save_btn.click()
|
||||
|
||||
driver.find_element(By.XPATH, '//button[contains(@ng-click, "dismissModal()")]').click()
|
||||
rows = get_reservation_rows()
|
||||
|
||||
die()
|
||||
Loading…
Reference in New Issue
Block a user