Job signoffs now functional under this branch

This commit is contained in:
Jacob Henry 2019-03-01 00:25:33 -05:00
parent e74c9dcaa6
commit 7f1e105843
2 changed files with 57 additions and 42 deletions

View File

@ -1,5 +1,5 @@
from dataclasses import dataclass
from typing import List, Match, Callable, TypeVar, Optional, Iterable
from typing import List, Match, Callable, TypeVar, Optional, Iterable, Any, Coroutine
from fuzzywuzzy import fuzz
@ -60,7 +60,7 @@ class _ModJobContext:
async def _mod_jobs(event: slack_util.Event,
relevance_scorer: Callable[[house_management.JobAssignment], Optional[float]],
modifier: Callable[[_ModJobContext], None],
modifier: Callable[[_ModJobContext], Coroutine[Any, Any, None]],
no_job_msg: str = None
) -> None:
"""
@ -98,7 +98,7 @@ async def _mod_jobs(event: slack_util.Event,
context = _ModJobContext(signer, fresh_targ_assign)
# Modify it
modifier(context)
await modifier(context)
# Re-upload
await house_management.export_assignments(fresh_assigns)
@ -164,14 +164,14 @@ async def signoff_callback(event: slack_util.Event, match: Match) -> None:
return r
# Set the assigner, and notify
def modifier(context: _ModJobContext):
async def modifier(context: _ModJobContext):
context.assign.signer = context.signer
# Say we did it wooo!
slack_util.get_slack().reply(event, "Signed off {} for {}".format(context.assign.assignee.name,
context.assign.job.name))
alert_user(context.assign.assignee, "{} signed you off for {}.".format(context.assign.signer.name,
context.assign.job.pretty_fmt()))
await alert_user(context.assign.assignee, "{} signed you off for {}.".format(context.assign.signer.name,
context.assign.job.pretty_fmt()))
# Fire it off
await _mod_jobs(event, scorer, modifier)
@ -192,15 +192,15 @@ async def undo_callback(event: slack_util.Event, match: Match) -> None:
return r
# Set the assigner to be None, and notify
def modifier(context: _ModJobContext):
async def modifier(context: _ModJobContext):
context.assign.signer = None
# Say we did it wooo!
slack_util.get_slack().reply(event, "Undid signoff of {} for {}".format(context.assign.assignee.name,
context.assign.job.name))
alert_user(context.assign.assignee, "{} undid your signoff off for {}.\n"
"Must have been a mistake".format(context.assign.signer.name,
context.assign.job.pretty_fmt()))
await alert_user(context.assign.assignee, "{} undid your signoff off for {}.\n"
"Must have been a mistake".format(context.assign.signer.name,
context.assign.job.pretty_fmt()))
# Fire it off
await _mod_jobs(event, scorer, modifier)
@ -221,7 +221,7 @@ async def late_callback(event: slack_util.Event, match: Match) -> None:
return r
# Just set the assigner
def modifier(context: _ModJobContext):
async def modifier(context: _ModJobContext):
context.assign.late = not context.assign.late
# Say we did it
@ -253,7 +253,7 @@ async def reassign_callback(event: slack_util.Event, match: Match) -> None:
return r
# Change the assignee
def modifier(context: _ModJobContext):
async def modifier(context: _ModJobContext):
context.assign.assignee = to_bro
# Say we did it
@ -266,8 +266,8 @@ async def reassign_callback(event: slack_util.Event, match: Match) -> None:
reassign_msg = "Job {} reassigned from {} to {}".format(context.assign.job.pretty_fmt(),
from_bro,
to_bro)
alert_user(from_bro, reassign_msg)
alert_user(to_bro, reassign_msg)
await alert_user(from_bro, reassign_msg)
await alert_user(to_bro, reassign_msg)
# Fire it off
await _mod_jobs(event, scorer, modifier)
@ -360,7 +360,7 @@ signoff_hook = slack_util.ChannelHook(signoff_callback,
r"signoff\s+(.*)",
r"sign off\s+(.*)",
],
channel_whitelist=["#housejobs"])
channel_whitelist=["#botzone"])
undo_hook = slack_util.ChannelHook(undo_callback,
patterns=[

View File

@ -1,5 +1,5 @@
from __future__ import annotations
from aiohttp import web
import asyncio
import re
import sys
@ -129,25 +129,7 @@ def message_stream(slack: SlackClient) -> Generator[Event, None, None]:
# Handle each
for update in update_list:
print("Message received: {}".format(update))
event = Event()
# Big logic folks
if update["type"] == "message":
# For now we only handle these basic types of messages involving text
# TODO: Handle "unwrappeable" messages
if "text" in update and "ts" in update:
event.message = MessageContext(update["ts"], update["text"])
if "channel" in update:
event.conversation = ConversationContext(update["channel"])
if "user" in update:
event.user = UserContext(update["user"])
if "thread_ts" in update:
event.thread = ThreadContext(update["thread_ts"])
# TODO: Handle more types
# We need to
yield event
yield dict_to_event(update)
except (SlackNotConnected, OSError) as e:
print("Error while reading messages:")
@ -160,6 +142,30 @@ def message_stream(slack: SlackClient) -> Generator[Event, None, None]:
print("Connection failed - retrying")
def dict_to_event(update: dict) -> Event:
"""
Converts a dict update to an actual event.
"""
event = Event()
# Big logic folks
if update["type"] == "message":
# For now we only handle these basic types of messages involving text
# TODO: Handle "unwrappeable" messages
if "text" in update and "ts" in update:
event.message = MessageContext(update["ts"], update["text"])
if "channel" in update:
event.conversation = ConversationContext(update["channel"])
if "user" in update:
event.user = UserContext(update["user"])
if "thread_ts" in update:
event.thread = ThreadContext(update["thread_ts"])
# TODO: Handle more types of events, including http data etc.
return event
"""
Objects to wrap slack connections
"""
@ -254,8 +260,19 @@ class ClientWrapper(object):
yield await asyncio.get_running_loop().run_in_executor(None, get_one)
async def http_event_feed(self) -> AsyncGenerator[Event, None]:
# Create a callback to convert requests to events
async def interr(request: web.Request):
return web.Response()
# Create the server
pass
app = web.Application()
app.add_routes([web.get('/bothttpcallback/', interr)])
# Asynchronously serve that boy up
runner = web.AppRunner(app)
await runner.setup()
site = web.TCPSite(runner, 'localhost', 8080)
await site.start()
while True:
await asyncio.sleep(30)
@ -293,14 +310,14 @@ class ClientWrapper(object):
def get_conversation_by_name(self, conversation_identifier: str) -> Optional[Conversation]:
# If looking for a direct message, first lookup user, then fetch
if conversation_identifier[0] == "@":
user_name = conversation_identifier[1:]
user_name = conversation_identifier
# Find the user by their name
raise NotImplementedError("There wasn't a clear use case for this yet, so we've opted to just not use it")
# If looking for a channel, just lookup normally
elif conversation_identifier[0] == "#":
channel_name = conversation_identifier[1:]
channel_name = conversation_identifier
# Find the channel in the dict
for channel in self.conversations.values():
@ -383,10 +400,10 @@ class ClientWrapper(object):
for channel_dict in channel_dicts["channels"]:
if channel_dict["is_im"]:
new_channel = DirectMessage(id=channel_dict["id"],
user_id=channel_dict["user"])
user_id="@" + channel_dict["user"])
else:
new_channel = Channel(id=channel_dict["id"],
name=channel_dict["name"])
name="#" + channel_dict["name"])
new_dict[new_channel.id] = new_channel
# Fetch the cursor
@ -513,8 +530,6 @@ class ChannelHook(AbsHook):
if not (event.conversation and event.message and isinstance(event.conversation.get_conversation(), Channel)):
return None
# Fail if pattern invalid
match = None
for p in self.patterns: