commit b0e0a7e78d86471a075d5851dd71adb202609fab Author: Benson Chu Date: Fri Oct 26 18:21:10 2018 -0500 And God said, "Let there be light" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..83fb452 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.json +__pycache__ +time.txt +*.log diff --git a/mail.py b/mail.py new file mode 100755 index 0000000..dd281e4 --- /dev/null +++ b/mail.py @@ -0,0 +1,55 @@ +from email.mime.multipart import MIMEMultipart +from email.mime.text import MIMEText +from email.mime.base import MIMEBase +from email.mime.image import MIMEImage +from email import encoders +import smtplib +import os +import json +import subprocess + +def take_screenshot(): + filename = "./screenshot.png" + subprocess.call(["scrot", filename]) + return filename + + +def send_email(login_file): + picture_name = take_screenshot() + + json_data = open(login_file).read() + data = json.loads(json_data) + fromaddr = toaddr = data["email_address"] + password = data["password"] + + msg = MIMEMultipart() + + msg['From'] = fromaddr + msg['To'] = toaddr + msg['Subject'] = "Clock Status" + + body = "Hello, world!" + + msg.attach(MIMEText(body, 'plain')) + + filename = "time.txt" + #attachment = open("./time.txt", "rb") + picture = open(picture_name, "rb") + + #part = MIMEBase('application', 'octet-stream') + #part.set_payload((attachment).read()) + #encoders.encode_base64(part) + #part.add_header('Content-Disposition', "attachment; filename= %s" % filename) + #msg.attach(part) + + image = MIMEImage(picture.read(), name=os.path.basename(picture_name)) + msg.attach(image) + + server = smtplib.SMTP('smtp.gmail.com', 587) + server.starttls() + server.login(fromaddr, password) + text = msg.as_string() + server.sendmail(fromaddr, toaddr, text) + server.quit() + + os.remove(picture_name) diff --git a/pyclock.py b/pyclock.py new file mode 100644 index 0000000..6f9a4b7 --- /dev/null +++ b/pyclock.py @@ -0,0 +1,194 @@ +import argparse +import json +import getpass +import time +import datetime as dt +import os +from enum import IntEnum +from mail import send_email +from selen_help import * + +class Clock(IntEnum): + In = 1 + Out = 2 + Meal = 3 + + def __str__(self): + return self.name + + @staticmethod + def from_string(s): + try: + return Clock[s] + except KeyError: + raise ValueError() + + +def login(driver, username, password): + wait_for_internet_connection() + + driver.get("https://accessuh.uh.edu") + find_element(driver, By.ID, "param1").send_keys(username) + find_element(driver, By.ID, "param2").send_keys(password) + find_element(driver, By.XPATH, "/html/body/main/div/section/div[2]/form/div/div[1]/i/input").click() + + elem = find_element(driver, By.XPATH, "/html/body/main/div/div[2]/div/div[2]/div[2]/a") + driver.execute_script("arguments[0].setAttribute('target', '_self')", + elem) + driver.execute_script("arguments[0].click()", + elem) + + find_element(driver, By.ID, "win0divPTNUI_LAND_REC_GROUPLET$0").click() + find_element(driver, By.ID, "PT_SIDE$PIMG").click() + + +def select_action(driver, val): + select = Select(find_element(driver, By.ID, 'TL_RPTD_TIME_PUNCH_TYPE$0')) + select.select_by_value(str(int(val))) + + +def submit_form(driver): + elem = find_element(driver, By.ID, "TL_WEB_CLOCK_WK_TL_SAVE_PB") + driver.execute_script("arguments[0].setAttribute('onclick', \"submitAction_win0(document.win0, 'TL_WEB_CLOCK_WK_TL_SAVE_PB')\")", elem) + time.sleep(2) + elem.click() + + +def clock(action, username, password, email_status): + driver = webdriver.Firefox() + login(driver, username, password) + + select_action(driver, action) + + submit_form(driver) + timeClocked = dt.datetime.now() + + time.sleep(3) + + if email_status: + send_email("./email.json") + + time.sleep(3) + driver.quit() + + return timeClocked + + +def clockAt(action, username, password, end_time, quiet, email_status): + accurate_wait_until(end_time - dt.timedelta(seconds=30), quiet) + + driver = webdriver.Firefox() + login(driver, username, password) + select_action(driver, action) + + accurate_wait_until(end_time, quiet) + + submit_form(driver) + + time.sleep(3) + + if email_status: + send_email("./email.json") + + time.sleep(3) + driver.quit() + + +def main(): + parser = argparse.ArgumentParser() + + group = parser.add_mutually_exclusive_group(required=True) + group.add_argument('-c', '--clock', type=Clock.from_string, choices=list(Clock)) + group.add_argument('-b', '--both', action="store_true") + group.add_argument('-d', '--delayed', action="store_true") + group.add_argument("-i", "--interrupted", action="store_true") + group.add_argument("-n", "--navigate", action="store_true") + + group = parser.add_mutually_exclusive_group(required=True) + group.add_argument("-u", "--username") + group.add_argument("-f", "--file") + + parser.add_argument("-p", "--password") + + group = parser.add_mutually_exclusive_group() + group.add_argument("-et", "--elapsed_time", type=float) + group.add_argument("-t", "--time") + + parser.add_argument("-s", "--start") + + parser.add_argument("-m", "--minutes", action="store_true", help="Use minutes instead of hours") + + parser.add_argument("-q", "--quiet", action="store_true") + parser.add_argument("-e", "--email", action="store_true", help="Specify if you want to send an email with a screenshot") + + (args, extra) = parser.parse_known_args() + + if(args.file is not None): + json_data = open(args.file).read() + data = json.loads(json_data) + username = data["username"] + password = data["password"] + else: + username = args.username + if args.password is None: + password = getpass.getpass() + else: + password = args.password + + if args.clock is not None: + clock(args.clock, username, password) + elif args.navigate: + login(webdriver.Firefox(), username, password) + else: + if args.elapsed_time is not None: + if args.minutes: + elapse_time = dt.timedelta(minutes=args.elapsed_time) + else: + elapse_time = dt.timedelta(hours=args.elapsed_time) + + startTime = dt.datetime.now() + + if args.both: + startTime = clock(Clock.In, username, password, args.email) + + if args.time: + split = list(map(lambda x: int(x), args.time.split(':'))) + end_time = dt.datetime.now() \ + .replace(hour=split[0], + minute=split[1], + second=split[2]) + else: + if args.interrupted: + end_time = eval(open("time.txt", "r").read()) + else: + end_time = startTime + elapse_time + + f = open("time.txt", "w") + f.write(repr(end_time)) + f.close() + + clockAt(Clock.Out, + username, password, + end_time, + args.quiet, + args.email) + + os.remove("time.txt") + + +def accurate_sleep(delta_time, quiet): + end_time = now + delta_time + accurate_wait_until(end_time, quiet) + + +def accurate_wait_until(end_time, quiet): + now = dt.datetime.now() + while(now < end_time): + if not quiet: + print("Time Left: " + str(end_time-now), end='\r') + time.sleep(1) + now = dt.datetime.now() + + +if __name__ == "__main__": + main() diff --git a/redundancy/LaunchInterrupt b/redundancy/LaunchInterrupt new file mode 100755 index 0000000..239fa29 --- /dev/null +++ b/redundancy/LaunchInterrupt @@ -0,0 +1,3 @@ +#!/bin/bash + +PYTHON3_PATH="/home/benson/anaconda3/bin/python" xfce4-terminal --hold -T "Clock" -e 'zsh -c "neofetch; cd ~/workspace/python/pyclock; $PYTHON3_PATH ./pyclock.py -i -f file.json"' diff --git a/redundancy/ProcessExists b/redundancy/ProcessExists new file mode 100755 index 0000000..1aaba10 --- /dev/null +++ b/redundancy/ProcessExists @@ -0,0 +1,3 @@ +#!/bin/bash + +ps -aux | grep "pyclock.py" | grep -v "grep" | wc -l diff --git a/redundancy/restart.py b/redundancy/restart.py new file mode 100755 index 0000000..0d03197 --- /dev/null +++ b/redundancy/restart.py @@ -0,0 +1,12 @@ +#!/home/benson/anaconda3/bin/python +import os +import subprocess + +base_dir = os.path.dirname(os.path.realpath(__file__)) +result = subprocess.run(["%s/ProcessExists" % (base_dir)], stdout=subprocess.PIPE) +res = int(result.stdout) + +if res == 0 and os.path.isfile('%s/../time.txt' % (base_dir)): + subprocess.Popen('%s/LaunchInterrupt' % (base_dir)) +else: + print("Don't need to restart!") diff --git a/runfromcron b/runfromcron new file mode 100755 index 0000000..094f1ff --- /dev/null +++ b/runfromcron @@ -0,0 +1,2 @@ +export DISPLAY=:1 +python3 pyclock.py -b -f file.json -et 5 -e diff --git a/selen_help.py b/selen_help.py new file mode 100644 index 0000000..6abdd36 --- /dev/null +++ b/selen_help.py @@ -0,0 +1,32 @@ +from selenium import webdriver +from selenium.webdriver.support.ui import Select +from selenium.webdriver.common.by import By +import selenium.webdriver.common.by +import urllib3 +import certifi +import time + +def find_element(driver, by, text): + while True: + try: + return driver.find_element(by, text) + except Exception: + print("Waiting for page to load...", end='\r') + + +def wait_for_internet_connection(): + message = False + while True: + try: + urllib3.PoolManager( + cert_reqs='CERT_REQUIRED', + ca_certs=certifi.where()).request('GET', "https://google.com") +# print('Good connection.') + return True + except Exception: + if not message: + print('No connection! Please connect to the internet to continue.') + message = True + time.sleep(1) + +