Skip to content

Commit 4e82fed

Browse files
committed
Add exception handling for slack channel_not_found error
1 parent 3d2b1de commit 4e82fed

2 files changed

Lines changed: 55 additions & 23 deletions

File tree

pybot/__main__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from pybot.endpoints.slack.utils import PORT, HOST
1515
from pybot.endpoints.slack.utils import slack_configs
1616

17-
VERSION = "0.2.0"
17+
VERSION = "1.0"
1818
logger = logging.getLogger(__name__)
1919

2020

@@ -56,4 +56,4 @@ def make_sentry_logger():
5656
bot.router.add_get("/health", lambda request: Response(status=200))
5757
logging.getLogger('aiohttp.access').setLevel(logging.WARNING)
5858

59-
bot.start(host=HOST, port=PORT, print=False)
59+
bot.start(host=HOST, port=PORT, print=logger.info)

pybot/endpoints/slack/commands.py

Lines changed: 53 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1-
import logging, random
1+
import functools
2+
import logging
3+
import random
24

35
from sirbot import SirBot
46
from sirbot.plugins.slack import SlackPlugin
57
from slack import methods
68
from slack.commands import Command
9+
from slack.exceptions import SlackAPIError
710

811
from pybot.endpoints.slack.message_templates.commands import ticket_dialog, mentor_request_attachments
912
from pybot.endpoints.slack.utils import PYBACK_HOST, PYBACK_PORT, PYBACK_TOKEN, MODERATOR_CHANNEL
@@ -14,12 +17,6 @@
1417
logger = logging.getLogger(__name__)
1518

1619

17-
# TODO: write input-serializer for the input from the slash command. see repeated code in each slash command
18-
19-
20-
# TODO: write test to ensure these functions exist at compile time -unit
21-
# TODO: write test to ensure that the slack api that is being targeted has the slash commands - integration
22-
# TODO: write functionality to automatically add the slash command to slack api - integration
2320
def create_endpoints(plugin: SlackPlugin):
2421
plugin.on_command('/here', slash_here, wait=False)
2522
plugin.on_command('/lunch', slash_lunch, wait=False)
@@ -30,6 +27,38 @@ def create_endpoints(plugin: SlackPlugin):
3027
# plugin.on_command('/mentor', slash_mentor, wait=False)
3128

3229

30+
def catch_slack_error(func):
31+
"""
32+
Decorator for wrapping/catching exceptions thrown by
33+
the slack client and displaying an error to the user.
34+
35+
Only necessary (for now) for functions that post messages to
36+
slack channels
37+
"""
38+
39+
@functools.wraps(func)
40+
async def handler(command: Command, app: SirBot, *args, **kwargs):
41+
try:
42+
await func(command, app, *args, **kwargs)
43+
44+
except SlackAPIError:
45+
channel_id = command['channel_id']
46+
slash_command = command['command']
47+
slack_id = command['user_id']
48+
slack = app['plugins']['slack']
49+
50+
await slack.api.query(methods.CHAT_POST_EPHEMERAL, dict(
51+
user=slack_id,
52+
channel=slack_id,
53+
as_user=True,
54+
text=(f'Could not post result of `{slash_command}` '
55+
f'to channel <#{channel_id}>')
56+
))
57+
58+
return handler
59+
60+
61+
@catch_slack_error
3362
async def slash_mentor(command: Command, app: SirBot):
3463
airtable = app.plugins['airtable'].api
3564
services = await airtable.get_all_records('Services', 'Name')
@@ -43,9 +72,10 @@ async def slash_mentor(command: Command, app: SirBot):
4372
'channel': command['user_id'],
4473
'as_user': True,
4574
}
46-
await app.plugins["slack"].api.query(methods.CHAT_POST_MESSAGE, response)
75+
await app.plugins['slack'].api.query(methods.CHAT_POST_MESSAGE, response)
4776

4877

78+
@catch_slack_error
4979
async def slash_ticket(command: Command, app: SirBot):
5080
trigger_id = command['trigger_id']
5181
user_id = command['user_id']
@@ -55,13 +85,14 @@ async def slash_ticket(command: Command, app: SirBot):
5585
clicker_email = user_info['user']['profile']['email']
5686

5787
response = {
58-
"trigger_id": trigger_id,
59-
"dialog": ticket_dialog(clicker_email, command['text'])
88+
'trigger_id': trigger_id,
89+
'dialog': ticket_dialog(clicker_email, command['text'])
6090
}
6191

62-
await app.plugins["slack"].api.query(methods.DIALOG_OPEN, response)
92+
await app.plugins['slack'].api.query(methods.DIALOG_OPEN, response)
6393

6494

95+
@catch_slack_error
6596
async def slash_report(command: Command, app: SirBot):
6697
"""
6798
Sends text supplied with the /report command to the moderators channel along
@@ -70,7 +101,7 @@ async def slash_report(command: Command, app: SirBot):
70101
slack_id = command['user_id']
71102
text = command['text']
72103

73-
slack = app["plugins"]["slack"].api
104+
slack = app['plugins']['slack'].api
74105

75106
message = f'<@{slack_id}> sent report: {text}'
76107

@@ -83,14 +114,15 @@ async def slash_report(command: Command, app: SirBot):
83114
await slack.query(methods.CHAT_POST_MESSAGE, response)
84115

85116

117+
@catch_slack_error
86118
async def slash_here(command: Command, app: SirBot):
87119
"""
88120
/here allows admins to give non-admins the ability to use @here-esque functionality for specific channels.
89121
Queries pyback to determine if user is authorized
90122
"""
91123
channel_id = command['channel_id']
92124
slack_id = command['user_id']
93-
slack = app["plugins"]["slack"].api
125+
slack = app['plugins']['slack'].api
94126

95127
params = {'slack_id': slack_id, 'channel_id': channel_id}
96128
headers = {'Authorization': f'Token {PYBACK_TOKEN}'}
@@ -115,6 +147,7 @@ async def slash_here(command: Command, app: SirBot):
115147
await slack.query(methods.CHAT_POST_MESSAGE, {'channel': channel_id, 'text': member_list, 'thread_ts': timestamp})
116148

117149

150+
@catch_slack_error
118151
async def slash_lunch(command: Command, app: SirBot):
119152
"""
120153
Provides the user with a random restaurant in their area.
@@ -123,7 +156,7 @@ async def slash_lunch(command: Command, app: SirBot):
123156
lunch = LunchCommand(command['channel_id'], command['user_id'],
124157
command.get('text'), command['user_name'])
125158

126-
slack = app["plugins"]["slack"].api
159+
slack = app['plugins']['slack'].api
127160

128161
request = lunch.get_yelp_request()
129162
async with app.http_session.get(**request) as r:
@@ -133,26 +166,25 @@ async def slash_lunch(command: Command, app: SirBot):
133166
await slack.query(methods.CHAT_POST_EPHEMERAL, message_params)
134167

135168

169+
@catch_slack_error
136170
async def slash_repeat(command: Command, app: SirBot):
137171
logger.info(f'repeat command data incoming {command}')
138172
channel_id = command['channel_id']
139173
slack_id = command['user_id']
140-
slack = app["plugins"]["slack"].api
174+
slack = app['plugins']['slack'].api
141175

142176
method_type, message = get_slash_repeat_messages(slack_id, channel_id, command['text'])
177+
143178
await slack.query(method_type, message)
144179

145180

181+
@catch_slack_error
146182
async def slash_roll(command: Command, app: SirBot):
147-
"""
148-
Sends text supplied with the /report command to the moderators channel along
149-
with a button to claim the issue
150-
"""
151183
slack_id = command['user_id']
152184
channel_id = command['channel_id']
153185
text = command['text']
154186

155-
slack = app["plugins"]["slack"].api
187+
slack = app['plugins']['slack'].api
156188

157189
# parse the type of die and number to roll
158190
try:
@@ -165,7 +197,7 @@ async def slash_roll(command: Command, app: SirBot):
165197
if typedice <= 0 or typedice > 20:
166198
raise ValueError
167199
except ValueError:
168-
logger.debug("invalid input to roll: %s", text)
200+
logger.debug('invalid input to roll: %s', text)
169201
await slack.query(methods.CHAT_POST_EPHEMERAL,
170202
{'user': slack_id, 'channel': channel_id,
171203
'text': "Sorry, I didn't understand your input. Should be XDYY where X is the number of dice, and YY is the number of sides"})

0 commit comments

Comments
 (0)