Awaiting testing

This commit is contained in:
Jacob Henry 2019-02-22 05:27:03 -05:00
parent ddb6ffac10
commit c1dbe21c77
5 changed files with 170 additions and 51 deletions

View File

@ -2,7 +2,6 @@ from dataclasses import dataclass
from typing import List, Match, Callable, TypeVar, Optional, Iterable from typing import List, Match, Callable, TypeVar, Optional, Iterable
from fuzzywuzzy import fuzz from fuzzywuzzy import fuzz
from slackclient import SlackClient
import house_management import house_management
import identifier import identifier
@ -311,22 +310,27 @@ async def refresh_callback(event: slack_util.Event, match: Match) -> None:
async def nag_callback(event: slack_util.Event, match: Match) -> None: async def nag_callback(event: slack_util.Event, match: Match) -> None:
# Get the day # Get the day
day = match.group(1).lower().strip() day = match.group(1).lower().strip()
if not await nag_jobs(day):
slack_util.get_slack().reply(event,
"No jobs found. Check that the day is spelled correctly, with no extra symbols.\n"
"It is possible that all jobs have been signed off, as well.",
in_thread=True)
# Wrapper so we can auto-call this as well
async def nag_jobs(day_of_week: str) -> bool:
# Get the assigns # Get the assigns
assigns = await house_management.import_assignments() assigns = await house_management.import_assignments()
# Filter to day # Filter to day
assigns = [assign for assign in assigns if assign is not None and assign.job.day_of_week.lower() == day] assigns = [assign for assign in assigns if assign is not None and assign.job.day_of_week.lower() == day_of_week]
# Filter signed off # Filter signed off
assigns = [assign for assign in assigns if assign.signer is None] assigns = [assign for assign in assigns if assign.signer is None]
# If no jobs found, somethings up. Probably mispelled day. # If no jobs found, somethings up. Probably mispelled day. Return failure
if not assigns: if not assigns:
slack_util.get_slack().reply(event, "No jobs found. Check that the day is spelled correctly, with no extra symbols.\n" return False
"It is possible that all jobs have been signed off, as well.",
in_thread=True)
return
# Nag each # Nag each
response = "Do yer jerbs! They are as follows:\n" response = "Do yer jerbs! They are as follows:\n"
@ -347,7 +351,7 @@ async def nag_callback(event: slack_util.Event, match: Match) -> None:
response += "\n" response += "\n"
general_id = slack_util.get_slack().get_channel_by_name("#general").id general_id = slack_util.get_slack().get_channel_by_name("#general").id
slack_util.get_slack().reply(event, response, in_thread=False, to_channel=general_id) slack_util.get_slack().send_message(response, general_id)
signoff_hook = slack_util.ChannelHook(signoff_callback, signoff_hook = slack_util.ChannelHook(signoff_callback,

View File

@ -44,6 +44,9 @@ def main() -> None:
# Add boozebot # Add boozebot
# wrap.add_passive(periodicals.ItsTenPM()) # wrap.add_passive(periodicals.ItsTenPM())
# Add automatic updating of users
wrap.add_passive(periodicals.Updatinator(wrap, 60))
# Add nagloop # Add nagloop
wrap.add_passive(periodicals.RemindJobs()) wrap.add_passive(periodicals.RemindJobs())

View File

@ -4,6 +4,7 @@ from typing import Optional, List
import house_management import house_management
import identifier import identifier
import job_commands
import slack_util import slack_util
@ -30,14 +31,14 @@ class ItsTenPM(slack_util.Passive):
await asyncio.sleep(60) await asyncio.sleep(60)
class RemindJobs(slack_util.Passive): # Shared behaviour
async def run(self) -> None: class JobNotifier:
while True: @staticmethod
# Get the end of the current day (Say, 10PM) def get_day_of_week() -> str:
today_remind_time = datetime.now().replace(hour=22, minute=00, second=0) """
Gets the current day of week as a str
# Get the current day of week """
dow = ["Monday", return ["Monday",
"Tuesday", "Tuesday",
"Wednesday", "Wednesday",
"Thursday", "Thursday",
@ -45,20 +46,13 @@ class RemindJobs(slack_util.Passive):
"Saturday", "Saturday",
"Sunday"][datetime.now().weekday()] "Sunday"][datetime.now().weekday()]
# Sleep until that time @staticmethod
delay = seconds_until(today_remind_time) def is_job_valid(a: Optional[house_management.JobAssignment]):
await asyncio.sleep(delay)
# Now it is that time. Get the current jobs
assigns = await house_management.import_assignments()
# Filter to incomplete, and today
def valid_filter(a: Optional[house_management.JobAssignment]):
# If it doesn't exist, it a thot # If it doesn't exist, it a thot
if a is None: if a is None:
return False return False
# If its not today, we shouldn't nag # If its not today, we shouldn't nag
if a.job.day_of_week.lower() != dow.lower(): if a.job.day_of_week.lower() != JobNotifier.get_day_of_week().lower():
return False return False
# If it is unassigned, we can't nag # If it is unassigned, we can't nag
if a.assignee is None: if a.assignee is None:
@ -71,10 +65,42 @@ class RemindJobs(slack_util.Passive):
return False return False
return True return True
assigns: List[house_management.JobAssignment] = [a for a in assigns if valid_filter(a)]
class NotifyJobs(slack_util.Passive, JobNotifier):
async def run(self) -> None:
while True:
# Get the "Start" of the current day (Say, 10AM)
today_remind_time = datetime.now().replace(hour=10, minute=00, second=0)
# Sleep until that time
delay = seconds_until(today_remind_time)
await asyncio.sleep(delay)
# Now it is that time. Nag the jobs
job_commands.nag_jobs(self.get_day_of_week())
# Sleep for a bit to prevent double shots
await asyncio.sleep(10)
class RemindJobs(slack_util.Passive, JobNotifier):
async def run(self) -> None:
while True:
# Get the end of the current day (Say, 10PM)
today_remind_time = datetime.now().replace(hour=22, minute=00, second=0)
# Sleep until that time
delay = seconds_until(today_remind_time)
await asyncio.sleep(delay)
# Now it is that time. Get the current jobs
assigns = await house_management.import_assignments()
# Filter to incomplete, and today
assigns: List[house_management.JobAssignment] = [a for a in assigns if self.is_job_valid(a)]
# Now, we want to nag each person. If we don't actually know who they are, so be it. # Now, we want to nag each person. If we don't actually know who they are, so be it.
print("Nagging!") print("Reminding!")
for a in assigns: for a in assigns:
# Get the relevant slack ids # Get the relevant slack ids
assignee_ids = await identifier.lookup_brother_userids(a.assignee) assignee_ids = await identifier.lookup_brother_userids(a.assignee)
@ -92,3 +118,15 @@ class RemindJobs(slack_util.Passive):
# Take a break to ensure no double-shots # Take a break to ensure no double-shots
await asyncio.sleep(10) await asyncio.sleep(10)
class Updatinator(slack_util.Passive):
def __init__(self, wrapper_to_update: slack_util.ClientWrapper, interval_seconds: int):
self.wrapper_target = wrapper_to_update
self.interval = interval_seconds
async def run(self):
while True:
await asyncio.sleep(self.interval)
self.wrapper_target.update_channels()
self.wrapper_target.update_users()

View File

@ -27,7 +27,7 @@ Objects to represent things within a slack workspace
class User: class User:
id: str id: str
name: str name: str
real_name: str real_name: Optional[str]
email: Optional[str] email: Optional[str]
async def get_brother(self) -> Optional[scroll_util.Brother]: async def get_brother(self) -> Optional[scroll_util.Brother]:
@ -41,8 +41,6 @@ class User:
class Channel: class Channel:
id: str id: str
name: str name: str
purpose: str
members: List[User]
""" """
@ -109,7 +107,7 @@ def message_stream(slack: SlackClient) -> Generator[Event, None, None]:
# Do forever # Do forever
while True: while True:
try: try:
if slack.rtm_connect(with_team_state=True, auto_reconnect=True): if slack.rtm_connect(with_team_state=False, auto_reconnect=True):
print("Waiting for messages") print("Waiting for messages")
while True: while True:
sleep(0.1) sleep(0.1)
@ -171,6 +169,8 @@ class ClientWrapper(object):
# Cache users and channels # Cache users and channels
self.users: dict = {} self.users: dict = {}
self.channels: dict = {} self.channels: dict = {}
self.update_users()
self.update_channels()
# Scheduled events handling # Scheduled events handling
def add_passive(self, per: Passive) -> None: def add_passive(self, per: Passive) -> None:
@ -281,6 +281,83 @@ class ClientWrapper(object):
return self.api_call("chat.postMessage", **kwargs) return self.api_call("chat.postMessage", **kwargs)
def update_channels(self):
"""
Queries the slack API for all current channels
"""
# Necessary because of pagination
cursor = None
# Make a new dict to use
new_dict = {}
# Iterate over results
while True:
# Set args depending on if a cursor exists
args = {"limit": 1000, "type": "public_channel,private_channel,mpim,im"}
if cursor:
args["cursor"] = cursor
channel_dicts = self.api_call("https://slack.com/api/conversations.list", **args)
# If the response is good, put its results to the dict
if channel_dicts["ok"]:
for channel_dict in channel_dicts["channels"]:
new_channel = Channel(id=channel_dict["id"],
name=channel_dict["name"])
new_dict[new_channel.id] = new_channel
# If no new channels, just give it up
if len(channel_dicts["channels"]) == 0:
break
# Otherwise, fetch the cursor
cursor = channel_dicts.get("response_metadata").get("next_cursor")
else:
print("Warning: failed to retrieve channels")
break
self.channels = new_dict
def update_users(self):
"""
Queries the slack API for all current users
"""
# Necessary because of pagination
cursor = None
while True:
# Set args depending on if a cursor exists
args = {"limit": 1000}
if cursor:
args["cursor"] = cursor
user_dicts = self.api_call("https://slack.com/api/users.list", **args)
# Make a new dict to use
new_dict = {}
# If the response is good:
if user_dicts["ok"]:
for user_dict in user_dicts["members"]:
new_user = User(id=user_dict.get("id"),
name=user_dict.get("name"),
real_name=user_dict.get("real_name"),
email=user_dict.get("profile").get("email"))
new_dict[new_user.id] = new_user
# If no new channels, just give it up
if len(user_dicts["channels"]) == 0:
break
# Otherwise, fetch the cursor
cursor = user_dicts.get("response_metadata").get("next_cursor")
else:
print("Warning: failed to retrieve channels")
break
self.users = new_dict
# Create a single instance of the client wrapper # Create a single instance of the client wrapper
_singleton = ClientWrapper(SLACK_API) _singleton = ClientWrapper(SLACK_API)

View File

@ -2,10 +2,7 @@ import re
import textwrap import textwrap
from typing import Match from typing import Match
from slackclient import SlackClient
import house_management import house_management
import identifier
import slack_util import slack_util
from scroll_util import Brother from scroll_util import Brother