Job signoffs now functional under this branch
This commit is contained in:
parent
e74c9dcaa6
commit
7f1e105843
|
|
@ -1,5 +1,5 @@
|
||||||
from dataclasses import dataclass
|
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
|
from fuzzywuzzy import fuzz
|
||||||
|
|
||||||
|
|
@ -60,7 +60,7 @@ class _ModJobContext:
|
||||||
|
|
||||||
async def _mod_jobs(event: slack_util.Event,
|
async def _mod_jobs(event: slack_util.Event,
|
||||||
relevance_scorer: Callable[[house_management.JobAssignment], Optional[float]],
|
relevance_scorer: Callable[[house_management.JobAssignment], Optional[float]],
|
||||||
modifier: Callable[[_ModJobContext], None],
|
modifier: Callable[[_ModJobContext], Coroutine[Any, Any, None]],
|
||||||
no_job_msg: str = None
|
no_job_msg: str = None
|
||||||
) -> None:
|
) -> None:
|
||||||
"""
|
"""
|
||||||
|
|
@ -98,7 +98,7 @@ async def _mod_jobs(event: slack_util.Event,
|
||||||
context = _ModJobContext(signer, fresh_targ_assign)
|
context = _ModJobContext(signer, fresh_targ_assign)
|
||||||
|
|
||||||
# Modify it
|
# Modify it
|
||||||
modifier(context)
|
await modifier(context)
|
||||||
|
|
||||||
# Re-upload
|
# Re-upload
|
||||||
await house_management.export_assignments(fresh_assigns)
|
await house_management.export_assignments(fresh_assigns)
|
||||||
|
|
@ -164,14 +164,14 @@ async def signoff_callback(event: slack_util.Event, match: Match) -> None:
|
||||||
return r
|
return r
|
||||||
|
|
||||||
# Set the assigner, and notify
|
# Set the assigner, and notify
|
||||||
def modifier(context: _ModJobContext):
|
async def modifier(context: _ModJobContext):
|
||||||
context.assign.signer = context.signer
|
context.assign.signer = context.signer
|
||||||
|
|
||||||
# Say we did it wooo!
|
# Say we did it wooo!
|
||||||
slack_util.get_slack().reply(event, "Signed off {} for {}".format(context.assign.assignee.name,
|
slack_util.get_slack().reply(event, "Signed off {} for {}".format(context.assign.assignee.name,
|
||||||
context.assign.job.name))
|
context.assign.job.name))
|
||||||
alert_user(context.assign.assignee, "{} signed you off for {}.".format(context.assign.signer.name,
|
await alert_user(context.assign.assignee, "{} signed you off for {}.".format(context.assign.signer.name,
|
||||||
context.assign.job.pretty_fmt()))
|
context.assign.job.pretty_fmt()))
|
||||||
|
|
||||||
# Fire it off
|
# Fire it off
|
||||||
await _mod_jobs(event, scorer, modifier)
|
await _mod_jobs(event, scorer, modifier)
|
||||||
|
|
@ -192,15 +192,15 @@ async def undo_callback(event: slack_util.Event, match: Match) -> None:
|
||||||
return r
|
return r
|
||||||
|
|
||||||
# Set the assigner to be None, and notify
|
# Set the assigner to be None, and notify
|
||||||
def modifier(context: _ModJobContext):
|
async def modifier(context: _ModJobContext):
|
||||||
context.assign.signer = None
|
context.assign.signer = None
|
||||||
|
|
||||||
# Say we did it wooo!
|
# Say we did it wooo!
|
||||||
slack_util.get_slack().reply(event, "Undid signoff of {} for {}".format(context.assign.assignee.name,
|
slack_util.get_slack().reply(event, "Undid signoff of {} for {}".format(context.assign.assignee.name,
|
||||||
context.assign.job.name))
|
context.assign.job.name))
|
||||||
alert_user(context.assign.assignee, "{} undid your signoff off for {}.\n"
|
await alert_user(context.assign.assignee, "{} undid your signoff off for {}.\n"
|
||||||
"Must have been a mistake".format(context.assign.signer.name,
|
"Must have been a mistake".format(context.assign.signer.name,
|
||||||
context.assign.job.pretty_fmt()))
|
context.assign.job.pretty_fmt()))
|
||||||
|
|
||||||
# Fire it off
|
# Fire it off
|
||||||
await _mod_jobs(event, scorer, modifier)
|
await _mod_jobs(event, scorer, modifier)
|
||||||
|
|
@ -221,7 +221,7 @@ async def late_callback(event: slack_util.Event, match: Match) -> None:
|
||||||
return r
|
return r
|
||||||
|
|
||||||
# Just set the assigner
|
# Just set the assigner
|
||||||
def modifier(context: _ModJobContext):
|
async def modifier(context: _ModJobContext):
|
||||||
context.assign.late = not context.assign.late
|
context.assign.late = not context.assign.late
|
||||||
|
|
||||||
# Say we did it
|
# Say we did it
|
||||||
|
|
@ -253,7 +253,7 @@ async def reassign_callback(event: slack_util.Event, match: Match) -> None:
|
||||||
return r
|
return r
|
||||||
|
|
||||||
# Change the assignee
|
# Change the assignee
|
||||||
def modifier(context: _ModJobContext):
|
async def modifier(context: _ModJobContext):
|
||||||
context.assign.assignee = to_bro
|
context.assign.assignee = to_bro
|
||||||
|
|
||||||
# Say we did it
|
# 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(),
|
reassign_msg = "Job {} reassigned from {} to {}".format(context.assign.job.pretty_fmt(),
|
||||||
from_bro,
|
from_bro,
|
||||||
to_bro)
|
to_bro)
|
||||||
alert_user(from_bro, reassign_msg)
|
await alert_user(from_bro, reassign_msg)
|
||||||
alert_user(to_bro, reassign_msg)
|
await alert_user(to_bro, reassign_msg)
|
||||||
|
|
||||||
# Fire it off
|
# Fire it off
|
||||||
await _mod_jobs(event, scorer, modifier)
|
await _mod_jobs(event, scorer, modifier)
|
||||||
|
|
@ -360,7 +360,7 @@ signoff_hook = slack_util.ChannelHook(signoff_callback,
|
||||||
r"signoff\s+(.*)",
|
r"signoff\s+(.*)",
|
||||||
r"sign off\s+(.*)",
|
r"sign off\s+(.*)",
|
||||||
],
|
],
|
||||||
channel_whitelist=["#housejobs"])
|
channel_whitelist=["#botzone"])
|
||||||
|
|
||||||
undo_hook = slack_util.ChannelHook(undo_callback,
|
undo_hook = slack_util.ChannelHook(undo_callback,
|
||||||
patterns=[
|
patterns=[
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
from aiohttp import web
|
||||||
import asyncio
|
import asyncio
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
|
@ -129,25 +129,7 @@ def message_stream(slack: SlackClient) -> Generator[Event, None, None]:
|
||||||
# Handle each
|
# Handle each
|
||||||
for update in update_list:
|
for update in update_list:
|
||||||
print("Message received: {}".format(update))
|
print("Message received: {}".format(update))
|
||||||
event = Event()
|
yield dict_to_event(update)
|
||||||
|
|
||||||
# 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
|
|
||||||
|
|
||||||
except (SlackNotConnected, OSError) as e:
|
except (SlackNotConnected, OSError) as e:
|
||||||
print("Error while reading messages:")
|
print("Error while reading messages:")
|
||||||
|
|
@ -160,6 +142,30 @@ def message_stream(slack: SlackClient) -> Generator[Event, None, None]:
|
||||||
print("Connection failed - retrying")
|
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
|
Objects to wrap slack connections
|
||||||
"""
|
"""
|
||||||
|
|
@ -254,8 +260,19 @@ class ClientWrapper(object):
|
||||||
yield await asyncio.get_running_loop().run_in_executor(None, get_one)
|
yield await asyncio.get_running_loop().run_in_executor(None, get_one)
|
||||||
|
|
||||||
async def http_event_feed(self) -> AsyncGenerator[Event, None]:
|
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
|
# 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:
|
while True:
|
||||||
await asyncio.sleep(30)
|
await asyncio.sleep(30)
|
||||||
|
|
@ -293,14 +310,14 @@ class ClientWrapper(object):
|
||||||
def get_conversation_by_name(self, conversation_identifier: str) -> Optional[Conversation]:
|
def get_conversation_by_name(self, conversation_identifier: str) -> Optional[Conversation]:
|
||||||
# If looking for a direct message, first lookup user, then fetch
|
# If looking for a direct message, first lookup user, then fetch
|
||||||
if conversation_identifier[0] == "@":
|
if conversation_identifier[0] == "@":
|
||||||
user_name = conversation_identifier[1:]
|
user_name = conversation_identifier
|
||||||
|
|
||||||
# Find the user by their name
|
# 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")
|
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
|
# If looking for a channel, just lookup normally
|
||||||
elif conversation_identifier[0] == "#":
|
elif conversation_identifier[0] == "#":
|
||||||
channel_name = conversation_identifier[1:]
|
channel_name = conversation_identifier
|
||||||
|
|
||||||
# Find the channel in the dict
|
# Find the channel in the dict
|
||||||
for channel in self.conversations.values():
|
for channel in self.conversations.values():
|
||||||
|
|
@ -383,10 +400,10 @@ class ClientWrapper(object):
|
||||||
for channel_dict in channel_dicts["channels"]:
|
for channel_dict in channel_dicts["channels"]:
|
||||||
if channel_dict["is_im"]:
|
if channel_dict["is_im"]:
|
||||||
new_channel = DirectMessage(id=channel_dict["id"],
|
new_channel = DirectMessage(id=channel_dict["id"],
|
||||||
user_id=channel_dict["user"])
|
user_id="@" + channel_dict["user"])
|
||||||
else:
|
else:
|
||||||
new_channel = Channel(id=channel_dict["id"],
|
new_channel = Channel(id=channel_dict["id"],
|
||||||
name=channel_dict["name"])
|
name="#" + channel_dict["name"])
|
||||||
new_dict[new_channel.id] = new_channel
|
new_dict[new_channel.id] = new_channel
|
||||||
|
|
||||||
# Fetch the cursor
|
# Fetch the cursor
|
||||||
|
|
@ -513,8 +530,6 @@ class ChannelHook(AbsHook):
|
||||||
if not (event.conversation and event.message and isinstance(event.conversation.get_conversation(), Channel)):
|
if not (event.conversation and event.message and isinstance(event.conversation.get_conversation(), Channel)):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Fail if pattern invalid
|
# Fail if pattern invalid
|
||||||
match = None
|
match = None
|
||||||
for p in self.patterns:
|
for p in self.patterns:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue