Awaiting testing
This commit is contained in:
parent
ddb6ffac10
commit
c1dbe21c77
|
|
@ -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,
|
||||||
|
|
|
||||||
3
main.py
3
main.py
|
|
@ -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())
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue