Added reply callback procedure?

This commit is contained in:
Jacob Henry 2018-11-12 13:27:46 -05:00
parent 716ec52a98
commit 1ddfa7403b
5 changed files with 80 additions and 17 deletions

View File

@ -70,6 +70,7 @@ class ClientWrapper(object):
# Strip garbage
msg['text'] = msg['text'].strip()
print("Recv: \"{}\"".format(msg['text']))
print(msg)
# Msg is good
# Find which hook, if any, satisfies

View File

@ -36,6 +36,9 @@ class Job(object):
# Extra stuff, interpreted
day: Optional[date]
def pretty_fmt(self) -> str:
return "{} - {} at {}".format(self.name, self.day_of_week, self.house)
@dataclass
class JobAssignment(object):
@ -53,7 +56,6 @@ class JobAssignment(object):
late = "y" if self.late else "n"
return self.job.name, self.job.house, self.job.day_of_week, self.assignee.name, signer_name, late
@dataclass
class PointStatus(object):
"""

View File

@ -63,11 +63,9 @@ def do_signoff(slack: SlackClient, msg: dict, on_assign_index: int, by_brother:
house_management.export_points(headers, points)
# Then we respond cool!
slack_util.reply(slack, msg, "{} signed off {} for {} {} {}".format(on_assign.signer.name,
slack_util.reply(slack, msg, "{} signed off {} for {}".format(on_assign.signer.name,
on_assign.assignee.name,
on_assign.job.house,
on_assign.job.day_of_week,
on_assign.job.name))
on_assign.job.pretty_fmt()))
alert_user(slack, on_assign.assignee, "Your house job was signed off")
@ -108,7 +106,6 @@ async def signoff_callback(slack: SlackClient, msg: dict, match: Match) -> None:
if len(closest_assigns) == 0:
slack_util.reply(slack, msg, "Unable to find any jobs assigned to brother {} "
"(identified as {}).".format(signee_name, signee.name))
return
# If theres only one job, sign it off
elif len(closest_assigns) == 1:
@ -118,12 +115,37 @@ async def signoff_callback(slack: SlackClient, msg: dict, match: Match) -> None:
targ_assign_index = assigns.index(targ_assign)
do_signoff(slack, msg, targ_assign_index, signer)
return
# If theres multiple jobs, we need to get a follow up!
else:
slack_util.reply(slack, msg, "Dunno how to handle multiple jobs yet")
return
# Say we need more info
job_list = "\n".join("{}: {}".format(i, a.job.pretty_fmt()) for i, a in enumerate(closest_assigns))
slack_util.reply(slack, msg, "Multiple sign off options dectected for brother {}.\n"
"Please enter the number corresponding to the job you wish to "
"sign off:\n{}\nIf you do not respond within 60 seconds, the signoff will "
"expire.".format(signee_name, job_list))
# Establish a follow up command pattern
pattern = r"\d+"
# Make the follow up callback
async def foc(_slack: SlackClient, _msg: dict, _match: Match) -> None:
# Get the number out
index = int(_match.group(0))
# Check that its valid
if 0 <= index < len(closest_assigns):
# We now know what we're trying to sign off!
specific_targ_assign = closest_assigns[index]
specific_targ_assign_index = assigns.index(specific_targ_assign)
do_signoff(_slack, _msg, specific_targ_assign_index, signer)
else:
# They gave a bad index, or we were unable to find the assignment again.
slack_util.reply(_slack, _msg, "Invalid job index / job unable to be found. Start over from the "
"signoff step.")
# Make a listener hook
slack_util.ReplyWaiter(foc, pattern, msg["ts"], 60)
# noinspection PyUnusedLocal
@ -191,12 +213,12 @@ async def nag_callback(slack, msg, match):
signoff_hook = slack_util.Hook(signoff_callback,
pattern=r"testsignoff\s+(.*)",
pattern=r"signoff\s+(.*)",
channel_whitelist=[channel_util.HOUSEJOBS])
reset_hook = slack_util.Hook(reset_callback,
pattern=r"testreset signoffs",
channel_whitelist=[channel_util.COMMAND_CENTER_ID]) # COMMAND_CENTER_ID
pattern=r"reset signoffs",
channel_whitelist=[channel_util.COMMAND_CENTER_ID])
nag_hook = slack_util.Hook(nag_callback,
pattern=r"nagjobs\s*(.*)",

View File

@ -35,6 +35,7 @@ brothers_matches = [m for m in brothers_matches if m]
brothers: List[Brother] = [Brother(m.group(2), int(m.group(1))) for m in brothers_matches]
recent_brothers: List[Brother] = brothers[700:]
async def scroll_callback(slack: SlackClient, msg: dict, match: Match) -> None:
"""
Finds the scroll of a brother, or the brother of a scroll, based on msg text.
@ -54,7 +55,7 @@ async def scroll_callback(slack: SlackClient, msg: dict, match: Match) -> None:
result = "Couldn't find brother {}".format(query)
# Respond
slack_util.reply(slack, msg, result)
print(slack_util.reply(slack, msg, result))
def find_by_scroll(scroll: int) -> Optional[Brother]:
@ -82,7 +83,7 @@ class BadName(Exception):
"match ratio {}. Please type name better.".format(self.name, self.score, self.threshold)
def find_by_name(name: str, threshold: Optional[float] = None, recent_only: bool=False) -> Brother:
def find_by_name(name: str, threshold: Optional[float] = None, recent_only: bool = False) -> Brother:
"""
Looks up a brother by name. Raises exception if threshold provided and not met.
@ -110,4 +111,4 @@ def find_by_name(name: str, threshold: Optional[float] = None, recent_only: bool
raise BadName(found, score, threshold)
scroll_hook = slack_util.Hook(scroll_callback, pattern=r"scroll\s+(.*)")
scroll_hook = slack_util.Hook(scroll_callback, pattern=r"testscroll\s+(.*)")

View File

@ -1,5 +1,5 @@
import re
from time import sleep
from time import sleep, time
from typing import Any, Optional, Generator, Match, Callable, List, Coroutine
from slackclient import SlackClient
@ -141,10 +141,47 @@ class Hook(AbsHook):
return self.callback(slack, msg, match)
class ReplyWaiter(AbsHook):
"""
A special hook that only cares about replies to a given message.
"""
def __init__(self, callback: Callback, pattern: str, thread_ts: str, lifetime: float):
super().__init__(True)
self.callback = callback
self.pattern = pattern
self.thread_ts = thread_ts
self.lifetime = lifetime
self.start_time = time()
self.dead = False
def try_apply(self, slack: SlackClient, msg: dict) -> Optional[Coroutine[None, None, None]]:
# First check: are we dead of age yet?
time_alive = time() - self.start_time
should_expire = time_alive < self.lifetime
# If so, give up the ghost
if self.dead or should_expire:
raise DeadHook()
# Otherwise proceed normally
# Is the msg the one we care about? If not, ignore
if msg.get("thread_ts", None) != self.thread_ts:
return None
# Does it match the regex? if not, ignore
match = re.match(self.pattern, msg['text'], flags=re.IGNORECASE)
if match:
return self.callback(slack, msg, match)
else:
return None
class Passive(object):
"""
Base class for Periodical tasks, such as reminders and stuff
"""
async def run(self, slack: SlackClient) -> None:
# Run this passive routed through the specified slack client.
raise NotImplementedError()