def stop_log(): print("\n End of log session : " + TZDT.now().strftime("%b %d %Y %I:%M:%S %p") + "\n") sys.stdout = ORIG_STDOUT print("Log mode deactivated : " + TZDT.now().strftime("%b %d %Y %I:%M:%S %p") + "\n") logger.close()
def confirm_shift(confirm_button): if confirm_button is None: print("shift NOT confirmed, timestamp: " + TZDT.now().strftime("%I:%M:%S %p")) else: confirm_button.click() # click to confirm shift # print confirmation message when ConfirmShift page is stale wait_for_stale_elements(driver, confirm_button) print('Shift confirmed at: ' + TZDT.now().strftime("%I:%M:%S %p"))
def get_desired_shift_dates(schedule_dict, delta): # variable to hold output shifts_list = [] # get time now timeNow = TZDT.now() # add delta weeks to date desiredWeekday = timeNow + timedelta(weeks=delta) # adds delta weeks # get year, month and day for desiredWeekday dateTuple = date_to_tuple(desiredWeekday) desired_year = dateTuple[0] desired_month = dateTuple[1] desired_day = dateTuple[2] # convert desiredWeekday to weekday string format and find shift times in schedule weekdayFormat = desiredWeekday.strftime("%a") shifts_of_the_day = schedule_dict[ weekdayFormat] # this is a list of tuples # find start and end times in shift times for startTime, endTime in shifts_of_the_day: # make shift list in datetime format, include just the startTime _shiftStartTime = datetime(desired_year, desired_month, desired_day, startTime) _shiftEndTime = datetime(desired_year, desired_month, desired_day, endTime) tuple_shift_start_end = (_shiftStartTime, _shiftEndTime) shifts_list.append(tuple_shift_start_end) return shifts_list
def grab_shift(date_and_time_tuple, parsed_table, location_of_shift='Lab Assistance - Lamont'): # find shifts in shiftboard available_shifts = parsed_table # shiftboard_parser(tableRowXpath) # variable for input_starTime and input_endTime inputStartTime = date_and_time_tuple[0] inputEndTime = date_and_time_tuple[1] # extract just the date from input bare_y, bare_m, bare_d = date_to_tuple(inputStartTime) plain_date = datetime(bare_y, bare_m, bare_d) # extract just the hour from inputStartTime and inputEndTime and format it inputStartHour = inputStartTime.strftime("%I%p").lower().lstrip("0") inputEndHour = inputEndTime.strftime("%I%p").lower().lstrip("0") # find shift if plain_date in available_shifts: # get shifts and shifts' info on plain_date dictValues = available_shifts[plain_date] # Handle empty dictValues if dictValues == []: print("No shifts to grab today, or all shifts have already been taken") return None else: pass for shiftDateRange, shiftLocation, clickElement in dictValues: # Name shiftDataRange elements for readability shiftStartTime = shiftDateRange[0] shiftEndTime = shiftDateRange[1] # find shift by comparing shiftStartTime and shiftEndTime to shift hours if (shiftStartTime == inputStartHour) and (shiftEndTime == inputEndHour) and (shiftLocation == location_of_shift): # indicate that shift has been found print(shiftStartTime + "-" + shiftEndTime + " : " + shiftLocation + " : MATCH FOUND, deploying confirm button...") clickElement.click() # click to grab shift # find "take this shift button" TakeThisShift = patiently_find(driver, element_present, By.XPATH, TakeThisShiftXpath) TakeThisShift.click() # click to take shift # find "confirm shift" button ConfirmShift = patiently_find(driver, element_present, By.XPATH, ConfirmShiftXpath) # Return confirm shift button print('Confirm button deployed at: ' + TZDT.now().strftime("%I:%M:%S %p")) return ConfirmShift elif (shiftStartTime != inputStartHour) and (shiftEndTime != inputEndHour) and (shiftLocation != location_of_shift): print(shiftStartTime + "-" + shiftEndTime + " : " + shiftLocation + ": Time and Location mismatch, skipping...") elif shiftLocation != location_of_shift: print(shiftStartTime + "-" + shiftEndTime + " : " + shiftLocation + ": Location mismatch. Input loaction is unpreferred.") elif (shiftStartTime != inputStartHour) and (shiftEndTime != inputEndHour): print(shiftStartTime + "-" + shiftEndTime + " : " + shiftLocation + ": Time mismatch. skipping...") else: print(shiftStartTime + "-" + shiftEndTime + " : " + shiftLocation + ": Error in grab_shift function of browser_handler: None of the conditions match") elif plain_date not in available_shifts: print("Date mismatch") return None # return None for error handling else: print("Something went wrong with grab_shift") return None # return non if all do not match
def GUI_log(file_name, _data): if _data != "\n": my_file = open(file_name, "a") global FirstTime if FirstTime: my_file.write('\n\n') FirstTime = False my_file.write(TZDT.now().strftime("%b %d %Y %I:%M:%S %p") + " - " + str(_data) + "\n") my_file.close() else: pass # ignore \n
def check_if_shift_approching(schedule_list_of_tuples, delta, decrease_delta): for time in schedule_list_of_tuples: shiftStartTime = time[0] shiftEndTime = time[1] if (TZDT.now() + timedelta(weeks=delta)) >= ( shiftStartTime - timedelta(seconds=decrease_delta)): time_on_this_date = (timedelta(weeks=delta) + TZDT.now()) print( "Grabbing time approaching for " + date_to_short_hour(shiftStartTime) + "-" + date_to_short_hour(shiftEndTime) + " in " + str(timedelta.total_seconds(shiftStartTime - time_on_this_date)).split(".")[0] + " seconds") return time else: # troubleshooting if debugMode: print("...") else: pass return None
def main_x(): try: # startup message global FirstTimeInitiating if (FirstTimeInitiating): print("Program initiated on " + TZDT.now().strftime("%b %d %Y %I:%M:%S %p")) FirstTimeInitiating = False else: pass # get user input try: # Update storage file? if sys.argv[1].lower().find('yes') != -1: print("Clear command received, clearing storage file...") FM.clear_data_file(dailyShiftStore) print("Storage file cleared successfully") else: pass # specify location global LOCATION if sys.argv[1].lower().find('lamont') != -1: print("Specified location: LAMONT") LOCATION = LAMONT elif sys.argv[1].lower().find('cabot') != -1: print("Specified location: CABOT") LOCATION = CABOT else: print("Location not specified." ) # pass if location not specified sys.argv = [] # clear input except IndexError: pass # ignore this error ''' # Alternative code for requesting user input global FirstTimeInitiating if FirstTimeInitiating: if askyesno('Verify', 'Update storage data?'): print("Clear command received, clearing storage file...") FM.clear_data_file(dailyShiftStore) print("Storage file cleared successfully") FirstTimeInitiating = False else: pass # ignore else: pass # ignore ''' # variable to hold dersied shifts start times in a list shiftsOfTheDay = [] # check the mode (calendar mode or scheduler mode) if calendarMode: # check if record of shifts already exists in file, check date timestamp timestamp_storedData = None # variable to hold timestamp from stored file try: storedData = FM.load_data(dailyShiftStore) timestamp_storedData = storedData[ 0] # never use index with an empty tuple except EOFError: pass # do not alter value of timestamp stored data if (timestamp_storedData == SC.today_raw_date()): # data already exists thus retrieve shifts of the day ie index 1 of tuple print("Valid up-to-date shift data found in storage") shiftsOfTheDay = storedData[1] print("Storage data retrieved!") # Show retrieved data on GUI print("Today's available shifts:") for each_tuple in shiftsOfTheDay: print(SC.datetime_tuple_to_string_format(each_tuple)) if shiftsOfTheDay == []: # print none if no shifts available print(None) else: # get new data and write to file GUI.BAR_MODE = "loading" # initiation sequence print( "Calendar mode active. \nRetrieving data from shiftboard website" ) BH.launch_browser(address) # go to shiftbaord website BH.login(email, password) # login BH.goto_next_week(weekNo) # go to weekNo weeks ahead # extract table data from shiftboard parsedShiftboardTable_for_calendar = BH.shiftboard_parser( BH.tableRowXpath) # remove taken shifts parsedShiftboardTable_for_calendar = BH.remove_taken_shifts( parsedShiftboardTable_for_calendar) print("Shift filtering complete") # extract day's shifts in a list of tuples extractedDayShifts = BH.extract_day_shift_time( parsedShiftboardTable_for_calendar, weekNo) # convert shift time ranges to datetimes and get list of tuples of shifts tuple_of_date_and_shift_tuples = BH.shift_time_to_datetime_parser( extractedDayShifts) list_of_tuples_shift_times_of_day = tuple_of_date_and_shift_tuples[ 1] # list of shifts for this day # use calendar_manager functions to retrieve day schedule with free periods print("Extracting schedule data from calendar") search_date = tuple_of_date_and_shift_tuples[ 0] # get date on tuple list of extractedDayShifts list_free_periods = CLDM.retrieve_schedule_of_the_day( search_date) # list of free periods for this day # use calendar_manager functions to compare shift time to free periods for each_shift in list_of_tuples_shift_times_of_day: # check if free at shift times and add start times of shifts that work to shiftsOfTheDay isFree = CLDM.check_if_free_comparator( each_shift, list_free_periods) if isFree: # store start time and end times of each shift to shiftsOfTheDay list. shiftsOfTheDay.append(each_shift) else: pass # do nothing # remove duplicates from shiftsOfTheDay, also changes order of elements ie sets are unordered print("List of shifts compiled successfully") shiftsOfTheDay = list(set(shiftsOfTheDay)) # store to file for future sessions, include datestamp stored in dailyShiftStore print("Writing list of shifts to storage file...") FM.write_data(dailyShiftStore, (SC.today_raw_date(), shiftsOfTheDay)) print("Stored successfully") else: # schedule mode # get list of dates of desired shifts two weeks from now from scheduler shiftsOfTheDay = SC.get_desired_shift_dates(desiredShifts, weekNo) # switch to shift listening mode and enter loop print("Listening for shifts from " + LOCATION + "...") GUI.BAR_MODE = "listening" # switch display mode # Make the program loop forever while True: # get approaching shift two weeks from now, (30 seconds earlier) shiftToTake = SC.check_if_shift_approching(shiftsOfTheDay, weekNo, 30) # if exit button is pressed in GUI if GUI.exit_thread: break # check if its sleeping time elif SC.today_time(wakeHour, wakeMinute) > TZDT.now(): # go to sleep print("Sleeping time zzz") break # check if desired shifts is empty elif shiftsOfTheDay == []: # exit loop if empty if calendarMode: print( "You have no free periods or there are no more shifts available on \n" + shift_check_date.strftime("%b %d %Y")) else: print("Your schedule is empty on " + shift_check_date.strftime("%b %d %Y")) # exit break # check if shift is approaching elif shiftToTake is None: # keep waiting for shift to approach pass # SPC.spinner() # run the code below if approaching else: # GUI GUI.BAR_MODE = "loading" # wait for internet connectivity print("Checking for internet connectivity at " + TZDT.now().strftime("%b %d %Y %I:%M:%S %p")) while (not BH.connected()): # check if program has been aborted if GUI.exit_thread: break else: pass # keep waiting for internet connectivity # connection successful print("Internet connection established at " + TZDT.now().strftime("%b %d %Y %I:%M:%S %p")) # launch browser BH.launch_browser(address) # enter username and password and log in BH.login(email, password) # go to two weeks ahead BH.goto_next_week(weekNo) # parse shiftboard table parsedShiftboardTable = BH.shiftboard_parser(BH.tableRowXpath) # remove taken shifts parsedShiftboardTable = BH.remove_taken_shifts( parsedShiftboardTable) # get shift confirm button confirmBtn = BH.grab_shift(shiftToTake, parsedShiftboardTable, LOCATION) # check if get shift confirm button is empty if confirmBtn is None: # remove shift time from list and update record to file print("Could NOT find shift on shiftboard") shift_remover(shiftToTake, shiftsOfTheDay) # then call main main_x() else: pass # ignore if shift found # create function to abort shift grabbing if need be def abort_grabbing(): shift_remover(shiftToTake, shiftsOfTheDay) # remove shift main_x() # call main to abort # abort message ABORT_MESSAGE = SC.datetime_tuple_to_string_format( shiftToTake ) + '''\nThis shift will be taken in less than 30 seconds. Click below to cancel''' # confirm shift, wait until the time reaches GUI.BAR_MODE = "flashing" # change bar GUI # ask user if shift grabbing should be aborted GUI.final_shift_notification(15000, ABORT_MESSAGE, abort_grabbing) while ((TZDT.now() + timedelta(weeks=weekNo)) < (shiftToTake[0]) + timedelta(milliseconds=1)): # check if program has been aborted if GUI.exit_thread: break else: pass # ignore # confirm BH.confirm_shift(confirmBtn) GUI.BAR_MODE = "loading" # remove confirmed shift from list for this session and record to file shift_remover(shiftToTake, shiftsOfTheDay) # switch to shift listening mode mode once done print("Done.\nListening for shifts from " + LOCATION + "...") GUI.BAR_MODE = "listening" # BH.delay(5) # BH.exit_sequence() BH.delay(1) # delay for 1 second, decrease CPU cycle rate # print loop exit message timestamp = TZDT.now() print("Loop exit at :" + timestamp.strftime("%b %d %Y %I:%M:%S %p")) # set arbitrary variable for wakeTime, value will be updated below wakeTime = timestamp # find wake up time by increasing timestamp by 1 day, fix this with if statements if SC.today_time(wakeHour, wakeMinute) < TZDT.now() < SC.today_time( 23, 59): wakeTime = timestamp + timedelta(days=1) else: pass # dont add a day ie wake up in the morning the same day # extract current date from wakeTime wakeTime_year, wakeTime_month, wakeTime_day = SC.date_to_tuple( wakeTime) # date at 8:45am on the next day wakeTime = datetime(wakeTime_year, wakeTime_month, wakeTime_day, wakeHour, wakeMinute) # activate sleepmode and wait until 8:45am the next day to wake if not GUI.exit_thread: print("Sleep mode activated at :" + TZDT.now().strftime("%b %d %Y %I:%M:%S %p")) GUI.BAR_MODE = "sleeping" # uncomment when ready to commence while TZDT.now() < wakeTime: # if exit button pressed if GUI.exit_thread: BH.exit_sequence() GUI.exit_success = True # indicate to GUI that exit was successful quit() # exit all python scripts break else: GUI.gray_fade_in() GUI.gray_fade_out() BH.delay(3) # decrease CPU cycle rate by sleeeping # if exit button NOT pressed if not GUI.exit_thread: # wake up sequence print("Sleep mode deactivated. Waking up at :" + TZDT.now().strftime("%b %d %Y %I:%M:%S %p")) GUI.BAR_MODE = "listening" main_x() # call main to wake the program and listen for shifts else: pass except Exception as e: # print the exception raised print("PROGRAM ERROR DETECTED: ") print(str(e) + "\n") # wait for internet connectivity print("Checking for internet connectivity at " + TZDT.now().strftime("%b %d %Y %I:%M:%S %p")) while (not BH.connected()): # check if program has been aborted if GUI.exit_thread: break else: pass # keep waiting for internet connectivity # connection successful print("Internet connection established at " + TZDT.now().strftime("%b %d %Y %I:%M:%S %p")) # call main to re initiate the program main_x()
import sys # module to get input from user import stdout_GUI as GUI # gui for display # from tkMessageBox import askyesno # uncomment if switching to alternative input method import timezone_datetime as TZDT # program variables debugMode = False weekNo = 2 takenShifts = 'taken_shifts.txt' wakeHour = 8 # am wakeMinute = 50 # am calendarMode = True dailyShiftStore = 'daily_shift_store.txt' secret_data = 'secret.data' FirstTimeInitiating = True shift_check_date = TZDT.now() + timedelta(weeks=weekNo) # user variables email = FM.load_data(secret_data)[0] # get email from file password = FM.load_data(secret_data)[1] # get password from file address = 'https://www.shiftboard.com/log-in/' # shiftboard website address # shift related variables desiredShifts = SC.desiredShifts # shifts to grab LAMONT = 'LAMONT' CABOT = 'CABOT Studios' LOCATION = LAMONT # system default for location # program functions
def start_log(): print("Log mode active. Redirecting ouput to logfile") sys.stdout = logger print("\n New log session : " + TZDT.now().strftime("%b %d %Y %I:%M:%S %p") + "\n")
def exit_sequence(): print("Exit sequence initiated at : " + TZDT.now().strftime("%b %d %Y %I:%M:%S %p") + ". Closing browser and exiting program.") driver.quit() # close browser after done
def today_time(_hour, _minute): _year, _month, _day = date_to_tuple(TZDT.now()) return datetime(_year, _month, _day, _hour, _minute)
def today_raw_date(): _y, _m, _d = date_to_tuple(TZDT.now()) return datetime(_y, _m, _d)