Skip to content

Commit

Permalink
wip: Add a message checker to the dispatcher
Browse files Browse the repository at this point in the history
  • Loading branch information
rebkwok committed Apr 18, 2024
1 parent 6891992 commit 84e370c
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 11 deletions.
10 changes: 9 additions & 1 deletion DEPLOY.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,13 @@ events. We need to add some more:
- `chat:write`
- `files:write`

### Add User scopes
We need a User token for the app in order to search slack messages:
1. Features > OAuth & Permissions: scroll down to Scopes. User Token Scopes
are found after the Bot Token Scopes. By default the app has no user scopes.
2. Add the following scopes:
- `search:read`

### Allow users to DM the app
1. Features > App Home
2. Under Messages Tabs, ensure the "Allow users to send Slash commands and messages from
Expand All @@ -71,7 +78,7 @@ events. We need to add some more:
### Install the app
1. Features > OAuth & Permissions
2. Under "OAuth Tokens for Your Workspace", click "Install to Workspace"
3. This will generate the bot token (starts `xoxb-`)
3. This will generate the bot token (starts `xoxb-`) and the user token (starts `xoxp-`)

If you update any scopes after installing the app, you'll need to reinstall it (slack will
usually prompt for this).
Expand Down Expand Up @@ -135,6 +142,7 @@ The following slack environment variables need to be set:
- `SLACK_TECH_SUPPORT_CHANNEL`: channel where tech-support requests will be reposted
- `SLACK_APP_TOKEN`: app-level token generated above (starts `xapp-`); found on the app's Basic Information page
- `SLACK_BOT_TOKEN`: bot token generated above (starts `xoxb-`); found on the app's Oauth and Permissions page
- `SLACK_BOT_USER_TOKEN`: user token generated above (starts `xoxp-`); found on the app's Oauth and Permissions page
- `SLACK_SIGNING_SECRET`: Found on the app's Basic Information page, under App Credentials
- `SLACK_APP_USERNAME`: The app's default name (and the name users will refer to the Bot as in Slack); found under Features > App Home

Expand Down
72 changes: 62 additions & 10 deletions ebmbot/dispatcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,44 +18,59 @@
from .slack import notify_slack


CHECKED = None


def run(): # pragma: no cover
"""Start the dispatcher running."""
slack_user_client = WebClient(token=settings.SLACK_BOT_USER_TOKEN)
slack_client = WebClient(token=settings.SLACK_BOT_TOKEN)

tech_support_channel = get_tech_support_channel(slack_client)
checker = MessageChecker(slack_user_client, tech_support_channel)
checker.run_check()
while True:
run_once(slack_client, job_configs.config)
run_once(
slack_client, job_configs.config, tech_support_channel=tech_support_channel
)
time.sleep(1)


def run_once(slack_client, config):
def run_once(slack_client, config, tech_support_channel=None):
"""Clear any expired suppressions, then start a new subprocess for each
available job.
We collect and return started processes so that we can wait for them to
finish in tests before asserting the tests have done anything.
"""

tech_support_channel = tech_support_channel or get_tech_support_channel(
slack_client
)
scheduler.remove_expired_suppressions()

processes = []

while True:
job_id = scheduler.reserve_job()
if job_id is None:
break
job_dispatcher = JobDispatcher(slack_client, job_id, config)
job_dispatcher = JobDispatcher(
slack_client, job_id, config, tech_support_channel
)
processes.append(job_dispatcher.start_job())

return processes


def get_tech_support_channel(slack_client):
return get_channels(slack_client)[settings.SLACK_TECH_SUPPORT_CHANNEL]


class JobDispatcher:
def __init__(self, slack_client, job_id, config):
def __init__(self, slack_client, job_id, config, tech_support_channel=None):
logger.info("starting job", job_id=job_id)
self.slack_client = slack_client
self.tech_support_channel = get_channels(self.slack_client)[
settings.SLACK_TECH_SUPPORT_CHANNEL
]
self.tech_support_channel = tech_support_channel or get_tech_support_channel(
self.slack_client
)
self.job = scheduler.get_job(job_id)
self.job_config = config["jobs"][self.job["type"]]

Expand Down Expand Up @@ -207,6 +222,43 @@ def set_up_log_dir(self):
self.log_dir.mkdir(parents=True, exist_ok=True)


class MessageChecker:
def __init__(self, slack_client, tech_support_channel=None):
self.slack_client = slack_client
self.tech_support_channel = tech_support_channel or get_tech_support_channel(
self.slack_client
)

def run_check(self):
"""Start running the check in a new subprocess."""
p = Process(target=self.do_check)
p.start()
return p

def do_check(self):
while True:
logger.info("Checking tech-support messages")
# TODO handle pagination (maybe not necessary if including date)
# Ignore messages from bots
# include a from: date to limit messages
# Ignore messages with repost links (keyword will not be in message text)
# i.e. we don't want to re-sos a message that is just copy/pasting another
# message that included the keyword
messages = self.slack_client.search_messages(
query=(
"tech-support -has::sos: "
f"-in:#{settings.SLACK_TECH_SUPPORT_CHANNEL} "
f"-from:@{settings.SLACK_APP_USERNAME}"
)
)["messages"]["matches"]
for message in messages:
logger.info("Messages", message=message["text"])
# TODO add sos, repost to tech-support channel

# TODO Also run for bennett-admins
time.sleep(5)


if __name__ == "__main__":
logger.info("running ebmbot.dispatcher")
run()
1 change: 1 addition & 0 deletions ebmbot/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
SLACK_BENNETT_ADMINS_CHANNEL = env.str("SLACK_BENNETT_ADMINS_CHANNEL")
SLACK_TECH_SUPPORT_CHANNEL = env.str("SLACK_TECH_SUPPORT_CHANNEL")
SLACK_BOT_TOKEN = env.str("SLACK_BOT_TOKEN")
SLACK_BOT_USER_TOKEN = env.str("SLACK_USER_TOKEN")
SLACK_APP_TOKEN = env.str("SLACK_APP_TOKEN")
SLACK_SIGNING_SECRET = env.str("SLACK_SIGNING_SECRET")
SLACK_APP_USERNAME = env.str("SLACK_APP_USERNAME")
Expand Down

0 comments on commit 84e370c

Please sign in to comment.