Things are less hacky now. WIP
This commit is contained in:
parent
b35593b89d
commit
fe33a5a0e4
|
|
@ -27,5 +27,5 @@ async def channel_check_callback(slack: SlackClient, msg: dict, match: Match) ->
|
||||||
slack_util.reply(slack, msg, response)
|
slack_util.reply(slack, msg, response)
|
||||||
|
|
||||||
|
|
||||||
channel_check_hook = slack_util.Hook(channel_check_callback,
|
channel_check_hook = slack_util.ChannelHook(channel_check_callback,
|
||||||
patterns=r"channel id\s*(.*)")
|
patterns=r"channel id\s*(.*)")
|
||||||
|
|
|
||||||
|
|
@ -123,5 +123,5 @@ class ClientWrapper(object):
|
||||||
_singleton = ClientWrapper()
|
_singleton = ClientWrapper()
|
||||||
|
|
||||||
|
|
||||||
def get_client_wrapper() -> ClientWrapper:
|
def grab() -> ClientWrapper:
|
||||||
return _singleton
|
return _singleton
|
||||||
|
|
|
||||||
|
|
@ -138,7 +138,7 @@ def lookup_brother_userids(brother: scroll_util.Brother) -> List[str]:
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
identify_hook = slack_util.Hook(identify_callback, patterns=r"my scroll is (.*)")
|
identify_hook = slack_util.ChannelHook(identify_callback, patterns=r"my scroll is (.*)")
|
||||||
identify_other_hook = slack_util.Hook(identify_other_callback, patterns=r"<@(.*)>\s+has scroll\s+(.*)")
|
identify_other_hook = slack_util.ChannelHook(identify_other_callback, patterns=r"<@(.*)>\s+has scroll\s+(.*)")
|
||||||
check_hook = slack_util.Hook(check_callback, patterns=r"what is my scroll")
|
check_hook = slack_util.ChannelHook(check_callback, patterns=r"what is my scroll")
|
||||||
name_hook = slack_util.Hook(name_callback, patterns=r"what is my name")
|
name_hook = slack_util.ChannelHook(name_callback, patterns=r"what is my name")
|
||||||
|
|
|
||||||
|
|
@ -149,7 +149,7 @@ async def _mod_jobs(slack: SlackClient,
|
||||||
new_hook = slack_util.ReplyWaiter(foc, pattern, msg["ts"], 120)
|
new_hook = slack_util.ReplyWaiter(foc, pattern, msg["ts"], 120)
|
||||||
|
|
||||||
# Register it
|
# Register it
|
||||||
client_wrapper.get_client_wrapper().add_hook(new_hook)
|
client_wrapper.grab().add_hook(new_hook)
|
||||||
|
|
||||||
|
|
||||||
async def signoff_callback(slack: SlackClient, msg: dict, match: Match) -> None:
|
async def signoff_callback(slack: SlackClient, msg: dict, match: Match) -> None:
|
||||||
|
|
@ -351,14 +351,14 @@ async def nag_callback(slack, msg, match):
|
||||||
slack_util.reply(slack, msg, response, in_thread=False, to_channel=channel_util.GENERAL)
|
slack_util.reply(slack, msg, response, in_thread=False, to_channel=channel_util.GENERAL)
|
||||||
|
|
||||||
|
|
||||||
signoff_hook = slack_util.Hook(signoff_callback,
|
signoff_hook = slack_util.ChannelHook(signoff_callback,
|
||||||
patterns=[
|
patterns=[
|
||||||
r"signoff\s+(.*)",
|
r"signoff\s+(.*)",
|
||||||
r"sign off\s+(.*)",
|
r"sign off\s+(.*)",
|
||||||
],
|
],
|
||||||
channel_whitelist=[channel_util.HOUSEJOBS])
|
channel_whitelist=[channel_util.HOUSEJOBS])
|
||||||
|
|
||||||
undo_hook = slack_util.Hook(undo_callback,
|
undo_hook = slack_util.ChannelHook(undo_callback,
|
||||||
patterns=[
|
patterns=[
|
||||||
r"unsignoff\s+(.*)",
|
r"unsignoff\s+(.*)",
|
||||||
r"undosignoff\s+(.*)",
|
r"undosignoff\s+(.*)",
|
||||||
|
|
@ -366,32 +366,32 @@ undo_hook = slack_util.Hook(undo_callback,
|
||||||
],
|
],
|
||||||
channel_whitelist=[channel_util.HOUSEJOBS])
|
channel_whitelist=[channel_util.HOUSEJOBS])
|
||||||
|
|
||||||
late_hook = slack_util.Hook(late_callback,
|
late_hook = slack_util.ChannelHook(late_callback,
|
||||||
patterns=[
|
patterns=[
|
||||||
r"marklate\s+(.*)",
|
r"marklate\s+(.*)",
|
||||||
r"mark late\s+(.*)",
|
r"mark late\s+(.*)",
|
||||||
],
|
],
|
||||||
channel_whitelist=[channel_util.HOUSEJOBS])
|
channel_whitelist=[channel_util.HOUSEJOBS])
|
||||||
|
|
||||||
reset_hook = slack_util.Hook(reset_callback,
|
reset_hook = slack_util.ChannelHook(reset_callback,
|
||||||
patterns=[
|
patterns=[
|
||||||
r"reset signoffs",
|
r"reset signoffs",
|
||||||
r"reset sign offs",
|
r"reset sign offs",
|
||||||
],
|
],
|
||||||
channel_whitelist=[channel_util.COMMAND_CENTER_ID])
|
channel_whitelist=[channel_util.COMMAND_CENTER_ID])
|
||||||
|
|
||||||
nag_hook = slack_util.Hook(nag_callback,
|
nag_hook = slack_util.ChannelHook(nag_callback,
|
||||||
patterns=[
|
patterns=[
|
||||||
r"nagjobs\s+(.*)",
|
r"nagjobs\s+(.*)",
|
||||||
r"nag jobs\s+(.*)"
|
r"nag jobs\s+(.*)"
|
||||||
],
|
],
|
||||||
channel_whitelist=[channel_util.COMMAND_CENTER_ID])
|
channel_whitelist=[channel_util.COMMAND_CENTER_ID])
|
||||||
|
|
||||||
reassign_hook = slack_util.Hook(reassign_callback,
|
reassign_hook = slack_util.ChannelHook(reassign_callback,
|
||||||
patterns=r"reassign\s+(.*?)->\s+(.+)",
|
patterns=r"reassign\s+(.*?)->\s+(.+)",
|
||||||
channel_whitelist=[channel_util.HOUSEJOBS])
|
channel_whitelist=[channel_util.HOUSEJOBS])
|
||||||
|
|
||||||
refresh_hook = slack_util.Hook(refresh_callback,
|
refresh_hook = slack_util.ChannelHook(refresh_callback,
|
||||||
patterns=[
|
patterns=[
|
||||||
"refresh points",
|
"refresh points",
|
||||||
"update points"
|
"update points"
|
||||||
|
|
|
||||||
4
main.py
4
main.py
|
|
@ -16,7 +16,7 @@ import slavestothemachine
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
wrap = client_wrapper.get_client_wrapper()
|
wrap = client_wrapper.grab()
|
||||||
|
|
||||||
# Add scroll handling
|
# Add scroll handling
|
||||||
wrap.add_hook(scroll_util.scroll_hook)
|
wrap.add_hook(scroll_util.scroll_hook)
|
||||||
|
|
@ -46,7 +46,7 @@ def main() -> None:
|
||||||
wrap.add_hook(job_commands.refresh_hook)
|
wrap.add_hook(job_commands.refresh_hook)
|
||||||
|
|
||||||
# Add help
|
# Add help
|
||||||
wrap.add_hook(slack_util.Hook(help_callback, patterns=[r"help", r"bot\s+help"]))
|
wrap.add_hook(slack_util.ChannelHook(help_callback, patterns=[r"help", r"bot\s+help"]))
|
||||||
|
|
||||||
# Add boozebot
|
# Add boozebot
|
||||||
# wrap.add_passive(periodicals.ItsTenPM())
|
# wrap.add_passive(periodicals.ItsTenPM())
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import channel_util
|
||||||
import slack_util
|
import slack_util
|
||||||
|
|
||||||
|
|
||||||
def list_hooks_callback_gen(hooks: List[slack_util.Hook]) -> slack_util.Callback:
|
def list_hooks_callback_gen(hooks: List[slack_util.ChannelHook]) -> slack_util.Callback:
|
||||||
# noinspection PyUnusedLocal
|
# noinspection PyUnusedLocal
|
||||||
async def callback(slack, msg, match):
|
async def callback(slack, msg, match):
|
||||||
slack_util.reply(slack, msg, "\n".join(hook.patterns for hook in hooks))
|
slack_util.reply(slack, msg, "\n".join(hook.patterns for hook in hooks))
|
||||||
|
|
@ -23,6 +23,6 @@ async def reboot_callback(slack: SlackClient, msg: dict, match: Match) -> None:
|
||||||
|
|
||||||
|
|
||||||
# Make hooks
|
# Make hooks
|
||||||
reboot_hook = slack_util.Hook(reboot_callback,
|
reboot_hook = slack_util.ChannelHook(reboot_callback,
|
||||||
patterns=r"reboot",
|
patterns=r"reboot",
|
||||||
channel_whitelist=[channel_util.COMMAND_CENTER_ID])
|
channel_whitelist=[channel_util.COMMAND_CENTER_ID])
|
||||||
|
|
|
||||||
|
|
@ -105,4 +105,4 @@ async def find_by_name(name: str, threshold: Optional[float] = None) -> Brother:
|
||||||
raise BrotherNotFound(msg)
|
raise BrotherNotFound(msg)
|
||||||
|
|
||||||
|
|
||||||
scroll_hook = slack_util.Hook(scroll_callback, patterns=r"scroll\s+(.*)")
|
scroll_hook = slack_util.ChannelHook(scroll_callback, patterns=r"scroll\s+(.*)")
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
|
from __future__ import annotations
|
||||||
import re
|
import re
|
||||||
|
from dataclasses import dataclass
|
||||||
from time import sleep, time
|
from time import sleep, time
|
||||||
from typing import Any, Optional, Generator, Match, Callable, List, Coroutine, Union, TypeVar, Awaitable
|
from typing import Any, Optional, Generator, Match, Callable, List, Coroutine, Union, TypeVar, Awaitable
|
||||||
|
|
||||||
|
|
@ -10,9 +12,10 @@ Slack helpers. Separated for compartmentalization
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
def reply(slack: SlackClient, msg: dict, text: str, in_thread: bool = True, to_channel: str = None) -> dict:
|
def reply(msg: dict, text: str, in_thread: bool = True, to_channel: str = None) -> dict:
|
||||||
"""
|
"""
|
||||||
Sends message with "text" as its content to the channel that message came from
|
Sends message with "text" as its content to the channel that message came from.
|
||||||
|
Returns the JSON response.
|
||||||
"""
|
"""
|
||||||
# If no channel specified, just do same as msg
|
# If no channel specified, just do same as msg
|
||||||
if to_channel is None:
|
if to_channel is None:
|
||||||
|
|
@ -27,9 +30,10 @@ def reply(slack: SlackClient, msg: dict, text: str, in_thread: bool = True, to_c
|
||||||
return send_message(slack, text, to_channel)
|
return send_message(slack, text, to_channel)
|
||||||
|
|
||||||
|
|
||||||
def send_message(slack: SlackClient, text: str, channel: str, thread: str = None, broadcast: bool = False) -> dict:
|
def send_message(text: str, channel: str, thread: str = None, broadcast: bool = False) -> dict:
|
||||||
"""
|
"""
|
||||||
Copy of the internal send message function of slack
|
Copy of the internal send message function of slack, with some helpful options.
|
||||||
|
Returns the JSON response.
|
||||||
"""
|
"""
|
||||||
kwargs = {"channel": channel, "text": text}
|
kwargs = {"channel": channel, "text": text}
|
||||||
if thread:
|
if thread:
|
||||||
|
|
@ -40,7 +44,58 @@ def send_message(slack: SlackClient, text: str, channel: str, thread: str = None
|
||||||
return slack.api_call("chat.postMessage", **kwargs)
|
return slack.api_call("chat.postMessage", **kwargs)
|
||||||
|
|
||||||
|
|
||||||
def message_stream(slack: SlackClient) -> Generator[dict, None, None]:
|
"""
|
||||||
|
Objects to represent things
|
||||||
|
"""
|
||||||
|
class User:
|
||||||
|
pass
|
||||||
|
|
||||||
|
class Channel:
|
||||||
|
@property
|
||||||
|
def channel_name(self) -> str:
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
Below we have a modular system that represents possible event contents.
|
||||||
|
"""
|
||||||
|
@dataclass
|
||||||
|
class Event:
|
||||||
|
channel: Optional[ChannelContext]
|
||||||
|
user: Optional[UserContext]
|
||||||
|
message: Optional[Message]
|
||||||
|
|
||||||
|
|
||||||
|
# If this was posted in a specific channel or conversation
|
||||||
|
@dataclass
|
||||||
|
class ChannelContext:
|
||||||
|
channel_id: str
|
||||||
|
|
||||||
|
|
||||||
|
# If there is a specific user associated with this event
|
||||||
|
@dataclass
|
||||||
|
class UserContext:
|
||||||
|
user_id: str
|
||||||
|
|
||||||
|
def as_user(self) -> User:
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
|
||||||
|
# Whether or not this is a threadable text message
|
||||||
|
@dataclass
|
||||||
|
class Message:
|
||||||
|
ts: str
|
||||||
|
text: str
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class File:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def message_stream(slack: SlackClient) -> Generator[Event, None, None]:
|
||||||
"""
|
"""
|
||||||
Generator that yields messages from slack.
|
Generator that yields messages from slack.
|
||||||
Messages are in standard api format, look it up.
|
Messages are in standard api format, look it up.
|
||||||
|
|
@ -83,35 +138,41 @@ class VerboseWrapper(Callable):
|
||||||
try:
|
try:
|
||||||
return await awt
|
return await awt
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
reply(self.slack, self.command_msg, "Error: {}".format(str(e)), True)
|
reply(self.command_msg, "Error: {}".format(str(e)), True)
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
|
|
||||||
|
# The result of a message
|
||||||
MsgAction = Coroutine[Any, Any, None]
|
MsgAction = Coroutine[Any, Any, None]
|
||||||
Callback = Callable[[SlackClient, dict, Match], MsgAction]
|
# The function called on a message
|
||||||
|
Callback = Callable[[SlackClient, Message, Match], MsgAction]
|
||||||
|
|
||||||
|
|
||||||
class DeadHook(Exception):
|
class DeadHook(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
# Abstract hook parent class
|
||||||
class AbsHook(object):
|
class AbsHook(object):
|
||||||
def __init__(self, consumes_applicable: bool):
|
def __init__(self, consumes_applicable: bool):
|
||||||
# Whether or not messages that yield a coroutine should not be checked further
|
# Whether or not messages that yield a coroutine should not be checked further
|
||||||
self.consumes = consumes_applicable
|
self.consumes = consumes_applicable
|
||||||
|
|
||||||
def try_apply(self, slack: SlackClient, msg: dict) -> Optional[Coroutine[None, None, None]]:
|
def try_apply(self, event: Event) -> Optional[MsgAction]:
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
|
||||||
class Hook(AbsHook):
|
class ChannelHook(AbsHook):
|
||||||
|
"""
|
||||||
|
Hook that handles messages in a variety of channels
|
||||||
|
"""
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
callback: Callback,
|
callback: Callback,
|
||||||
patterns: Union[str, List[str]],
|
patterns: Union[str, List[str]],
|
||||||
channel_whitelist: Optional[List[str]] = None,
|
channel_whitelist: Optional[List[str]] = None,
|
||||||
channel_blacklist: Optional[List[str]] = None,
|
channel_blacklist: Optional[List[str]] = None,
|
||||||
consumer: bool = True):
|
consumer: bool = True):
|
||||||
super(Hook, self).__init__(consumer)
|
super(ChannelHook, self).__init__(consumer)
|
||||||
|
|
||||||
# Save all
|
# Save all
|
||||||
if not isinstance(patterns, list):
|
if not isinstance(patterns, list):
|
||||||
|
|
@ -131,7 +192,7 @@ class Hook(AbsHook):
|
||||||
else:
|
else:
|
||||||
raise ValueError("Cannot whitelist and blacklist")
|
raise ValueError("Cannot whitelist and blacklist")
|
||||||
|
|
||||||
def try_apply(self, slack: SlackClient, msg: dict) -> Optional[Coroutine[None, None, None]]:
|
def try_apply(self, event: Event) -> Optional[MsgAction]:
|
||||||
"""
|
"""
|
||||||
Returns whether a message should be handled by this dict, returning a Match if so, or None
|
Returns whether a message should be handled by this dict, returning a Match if so, or None
|
||||||
"""
|
"""
|
||||||
|
|
@ -170,7 +231,7 @@ class ReplyWaiter(AbsHook):
|
||||||
self.start_time = time()
|
self.start_time = time()
|
||||||
self.dead = False
|
self.dead = False
|
||||||
|
|
||||||
def try_apply(self, slack: SlackClient, msg: dict) -> Optional[Coroutine[None, None, None]]:
|
def try_apply(self, event: Event) -> Optional[MsgAction]:
|
||||||
# First check: are we dead of age yet?
|
# First check: are we dead of age yet?
|
||||||
time_alive = time() - self.start_time
|
time_alive = time() - self.start_time
|
||||||
should_expire = time_alive > self.lifetime
|
should_expire = time_alive > self.lifetime
|
||||||
|
|
@ -199,6 +260,6 @@ class Passive(object):
|
||||||
Base class for Periodical tasks, such as reminders and stuff
|
Base class for Periodical tasks, such as reminders and stuff
|
||||||
"""
|
"""
|
||||||
|
|
||||||
async def run(self, slack: SlackClient) -> None:
|
async def run(self) -> None:
|
||||||
# Run this passive routed through the specified slack client.
|
# Run this passive routed through the specified slack client.
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ async def record_towel_contribution(for_brother: Brother, contribution_count: in
|
||||||
|
|
||||||
|
|
||||||
# Make dem HOOKs
|
# Make dem HOOKs
|
||||||
count_work_hook = slack_util.Hook(count_work_callback,
|
count_work_hook = slack_util.ChannelHook(count_work_callback,
|
||||||
patterns=".*",
|
patterns=".*",
|
||||||
channel_whitelist=[channel_util.SLAVES_TO_THE_MACHINE_ID],
|
channel_whitelist=[channel_util.SLAVES_TO_THE_MACHINE_ID],
|
||||||
consumer=False)
|
consumer=False)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue