1- import logging , random
1+ import functools
2+ import logging
3+ import random
24
35from sirbot import SirBot
46from sirbot .plugins .slack import SlackPlugin
57from slack import methods
68from slack .commands import Command
9+ from slack .exceptions import SlackAPIError
710
811from pybot .endpoints .slack .message_templates .commands import ticket_dialog , mentor_request_attachments
912from pybot .endpoints .slack .utils import PYBACK_HOST , PYBACK_PORT , PYBACK_TOKEN , MODERATOR_CHANNEL
1417logger = 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
2320def 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
3362async 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
4979async 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
6596async 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
86118async 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
118151async 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
136170async 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
146182async 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