diff --git a/.gitignore b/.gitignore index 1bdccaa..1420970 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ apitoken.txt killswitch.txt sheets_credentials.json -token.json +sheets_token.json *.bak *.dat *.dir diff --git a/channel_util.py b/channel_util.py index 00923ed..be436fa 100644 --- a/channel_util.py +++ b/channel_util.py @@ -7,6 +7,7 @@ GENERAL = "C0CFHPNEM" COMMAND_CENTER_ID = "GCR631LQ1" SLAVES_TO_THE_MACHINE_ID = "C9WUQBYNP" BOTZONE = "C3BF2MFKM" +HOUSEJOBS = "CDWDDTAT0" # Callback for telling what channel we in diff --git a/google_api.py b/google_api.py index 176f069..64f1f0c 100644 --- a/google_api.py +++ b/google_api.py @@ -10,12 +10,12 @@ from oauth2client import file, client, tools # If modifying these scopes, delete your previously saved credentials # at ~/.credentials/sheets.googleapis.com-python-quickstart.json -SCOPES = 'https://www.googleapis.com/auth/spreadsheets.readonly' -APPLICATION_NAME = 'My Project' +SCOPES = 'https://www.googleapis.com/auth/spreadsheets' +APPLICATION_NAME = 'SlickSlacker' def _init_sheets_service(): - store = file.Storage('token.json') + store = file.Storage('sheets_token.json') creds = store.get() if not creds or creds.invalid: flow = client.flow_from_clientsecrets('sheets_credentials.json', SCOPES) @@ -36,11 +36,25 @@ def get_sheet_range(spreadsheet_id, range): range=range).execute() values = result.get('values', []) if not values: - return None + return [] else: return values +def set_sheet_range(spreadsheet_id, range, values): + """ + Set an array in the desired table + """ + body = { + "values": values + } + result = _global_sheet_service.spreadsheets().values().update(spreadsheetId=spreadsheet_id, + range=range, + valueInputOption="RAW", + body=body).execute() + return result + + def get_calendar_credentials(): """Gets valid user credentials from storage. @@ -50,6 +64,7 @@ def get_calendar_credentials(): Returns: Credentials, the obtained credential. """ + """ home_dir = os.path.expanduser('~') credential_dir = os.path.join(home_dir, '.credentials') if not os.path.exists(credential_dir): @@ -67,3 +82,5 @@ def get_calendar_credentials(): credentials = tools.run(flow, store) print('Storing credentials to ' + credential_path) return credentials + """ + raise NotImplementedError("This isn't going to work") \ No newline at end of file diff --git a/job_signoff.py b/job_signoff.py new file mode 100644 index 0000000..a450101 --- /dev/null +++ b/job_signoff.py @@ -0,0 +1,118 @@ +from fuzzywuzzy import process + +import channel_util +import google_api +import slack_util + +SHEET_ID = "1lPj9GjB00BuIq9GelOWh5GmiGsheLlowPnHLnWBvMOM" + +# Note: These ranges use named range feature of google sheets. To edit range of jobs, edit the named range in Data -> Named Ranges +output_range = "JobScoreTracker" + +MIN_RATIO = 0.9 + + +# Used to track a sufficiently shitty typed name +class BadName(Exception): + def __init__(self, name, score): + self.name = name + self.score = score + + def as_response(self): + return "Unable to perform operation. Best name match {} had a match score of {}, falling short of match ratio " \ + "{}. Please type name better.".format(self.name, self.score, MIN_RATIO) + + +def get_curr_points(): + # Get the current stuff + curr_output = google_api.get_sheet_range(SHEET_ID, output_range) + + # Each element: force length of 2. + def row_fixer(r): + if len(r) == 0: + return ["", 0] + elif len(r) == 1: + return [r[0], 0] + else: + try: + v = int(r[1]) + except ValueError: + v = 0 + return [r[0], v] + + # Fix each row + curr_output = [row_fixer(x) for x in curr_output] + + # Cut off the chaff - doesn't seem to be necessary. + return curr_output + + +def put_points(vals): + google_api.set_sheet_range(SHEET_ID, output_range, vals) + + +def signoff_callback(slack, msg, match): + # Find the index of our person. + name = match.group(1) + try: + found_name, new_total = adjust_score(name, 1) + response = "Gave {} one housejob point. They now have {} for this period.".format(found_name, new_total) + except BadName as e: + response = e.as_response() + + slack_util.reply(slack, msg, response) + + +def punish_callback(slack, msg, match): + # Find the index of our person. + name = match.group(2) + try: + found_name, new_total = adjust_score(name, -1) + response = "Took one housejob point from {}. They now have {} for this period.".format(found_name, + new_total) + except BadName as e: + response = e.as_response() + + slack_util.reply(slack, msg, response) + + +def adjust_score(name, delta): + # Get the current stuff + points = get_curr_points() + names = [p[0] for p in points] + + # Find our guy + target_name, ratio = process.extractOne(name, names) + ratio = ratio / 100.0 + + # If bad ratio, error + if ratio < MIN_RATIO: + raise BadName(target_name, ratio) + + # Where is he in the list? + target_index = names.index(target_name) + + # Get his current score + curr_score = points[target_index][1] + + # target should be in the form index, (name, score) + target_new = [target_name, curr_score + delta] + + # Put it back + points[target_index] = target_new + put_points(points) + + # Return the adjusted name + return target_new + + +def reset_callback(slack, msg, match): + pass + # reset_callback() + + +signoff_hook = slack_util.Hook(signoff_callback, pattern=r"signoff\s+(.*)", + channel_whitelist=[channel_util.HOUSEJOBS]) +undosignoff_hook = slack_util.Hook(punish_callback, pattern=r"(unsignoff|undosignoff|undo)\s+(.*)", + channel_whitelist=[channel_util.HOUSEJOBS]) +# reset_hook = slack_util.Hook(reset_callback, pattern=r"reset_job_scores") diff --git a/main.py b/main.py index 5cd0efa..ddabf46 100644 --- a/main.py +++ b/main.py @@ -7,6 +7,7 @@ import management_commands import scroll_util import slack_util import slavestothemachine +import job_signoff from dummy import FakeClient # Read api token from file @@ -46,6 +47,10 @@ def main(): wrap.add_hook(slavestothemachine.count_work_hook) wrap.add_hook(slavestothemachine.dump_work_hook) + # Add signoffs + wrap.add_hook(job_signoff.signoff_hook) + wrap.add_hook(job_signoff.undosignoff_hook) + # Add help help_callback = management_commands.list_hooks_callback_gen(wrap.hooks) wrap.add_hook(slack_util.Hook(help_callback, pattern=management_commands.bot_help_pattern)) diff --git a/runloop.sh b/runloop.sh index a975552..01ff2bb 100755 --- a/runloop.sh +++ b/runloop.sh @@ -8,7 +8,9 @@ do git pull echo "Press [CTRL+C] to stop..." sleep 1 - python3 WaitonBot.py + touch script_log.txt + tail -n 1000 script_log.txt + python3 WaitonBot.py &>> script_log.txt sleep 1 echo "Died. Updating and restarting..." done