Skip to content

Commit e27333f

Browse files
authored
Merge branch 'master' into dependabot/pip/pip-21.1
2 parents 33940a8 + 3abc741 commit e27333f

File tree

8 files changed

+68
-3
lines changed

8 files changed

+68
-3
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"payload": "{\"type\":\"view_submission\",\"token\":\"ABCDEFGHIJKLMNOPQRSTUVWX\",\"team\":{\"id\":\"TEST_TEAM_ID\",\"domain\":\"test-team-name\"},\"user\":{\"id\":\"TEST_USER_ID\",\"name\":\"testusername\"},\"view\":{\"id\":\"VNHU13V36\",\"type\":\"modal\",\"title\":{ \"a\":\"b\" },\"submit\":{ \"a\":\"b\" },\"blocks\":[],\"private_metadata\":\"shhh-its-secret\",\"callback_id\":\"modal-with-inputs\",\"state\":{\"values\":{\"multiline\":{\"mlvalue\":{\"type\":\"plain_text_input\",\"value\":\"This is my example inputted value\"}},\"target_channel\":{\"target_select\":{\"type\":\"conversations_select\",\"selected_conversation\":\"C123B12DE\"}}}},\"hash\":\"156663117.cd33ad1f\",\"response_urls\":[{\"block_id\":\"target_channel\",\"action_id\":\"target_select\",\"channel_id\":\"C123B12DE\",\"response_url\":\"https:\\/\\/hooks.slack.com\\/app\\/ABC12312\\/1234567890\\/A100B100C100d100\"}]}}"
3+
}

data/test_omnibot_config.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,16 @@ handlers:
106106
- "echobot"
107107
callbacks:
108108
- module: "omnibot.handlers.interactive_component_handlers:echo_dialog_submission_handler"
109+
- callback_id: "modal-with-inputs"
110+
response_type: "in_channel"
111+
bots:
112+
"test-team-name":
113+
- "TEST_OMNIBOT_NAME"
114+
"testteam":
115+
- "echobot"
116+
callbacks:
117+
- module: "tests.data:test_handler"
118+
synchronous: true
109119
slash_command_handlers:
110120
- command: "/echo"
111121
response_type: "in_channel"

omnibot/processor.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,8 @@ def _handle_interactive_component_callback(component, callback, response_type):
453453
extra={**component.event_trace, 'callback': callback},
454454
)
455455
response = _handle_callback(component, callback)
456+
if response_type == 'raw':
457+
return response
456458
for component_response in response.get('responses', []):
457459
logger.debug(
458460
'Handling response for callback (pre-parse): {}'.format(

omnibot/routes/api.py

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,13 @@
2525
from omnibot.services import sqs
2626
from omnibot.services import stats
2727
from omnibot.services import slack
28+
from omnibot.services.slack.interactive_component import InteractiveComponent
2829
from omnibot.services.slack.team import Team
2930
from omnibot.services.slack.team import TeamInitializationError
3031
from omnibot.services.slack.bot import Bot
3132
from omnibot.services.slack.bot import BotInitializationError
3233
from omnibot.utils import get_callback_id, merge_logging_context
34+
from omnibot.processor import _handle_interactive_component_callback
3335

3436
logger = logging.getLogger(__name__)
3537

@@ -262,6 +264,7 @@ def slack_interactive_component():
262264
'message_action',
263265
'dialog_submission',
264266
'block_actions',
267+
'view_submission',
265268
]
266269
):
267270
msg = ('Unsupported type={} in interactive'
@@ -321,7 +324,10 @@ def slack_interactive_component():
321324
' associated with it.')
322325
logger.error(
323326
msg,
324-
extra=bot.logging_context,
327+
extra=merge_logging_context(
328+
{'callback_id': get_callback_id(component)},
329+
bot.logging_context,
330+
)
325331
)
326332
return jsonify({'response_type': 'ephemeral', 'text': msg}), 200
327333
# To avoid needing to look the bot up from its token when the dequeue this
@@ -332,6 +338,19 @@ def slack_interactive_component():
332338
# If there's no callbacks defined for this interactive component, we
333339
# can skip enqueuing it, since the workers will just discard it.
334340
if handler_found.get('callbacks'):
341+
callbacks = handler_found.get('callbacks')
342+
for c in callbacks:
343+
if c.get('synchronous'):
344+
interactive_component = InteractiveComponent(bot, component, {})
345+
resp = _handle_interactive_component_callback(interactive_component, c, 'raw')
346+
logger.info(
347+
'Synchronous callback response',
348+
extra=merge_logging_context(
349+
{'response': resp},
350+
bot.logging_context,
351+
)
352+
)
353+
return resp, 200
335354
queue_event(bot, component, 'interactive_component')
336355
except Exception:
337356
msg = 'Could not queue interactive component.'
@@ -711,7 +730,12 @@ def _perform_action(bot, data):
711730
)
712731
logger.debug(ret)
713732
if not ret['ok']:
714-
if ret.get('error') in ['missing_scope', 'not_allowed_token_type']:
733+
if ret.get('error') in {
734+
'missing_scope',
735+
'not_allowed_token_type',
736+
'channel_not_found',
737+
'not_in_channel',
738+
}:
715739
logger.warning(
716740
'action failed in post_slack, attempting as user.',
717741
extra=merge_logging_context(

omnibot/services/slack/interactive_component.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,9 @@ def __init__(self, bot, component, event_trace):
3232
self._payload['action_ts'] = component.get('action_ts')
3333
self._payload['message_ts'] = component.get('message_ts')
3434
self._payload['trigger_id'] = component.get('trigger_id')
35-
self._payload['response_url'] = component['response_url']
35+
self._payload['response_url'] = component.get('response_url')
3636
self._payload['original_message'] = component.get('original_message')
37+
self._payload['view'] = component.get('view')
3738
self._payload['state'] = component.get('state')
3839
self._payload['user'] = component.get('user')
3940
if self.user:

omnibot/utils/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ def get_callback_id(component):
1010
actions = component.get('actions', [])
1111
action = next(iter(actions))
1212
return action.get('block_id')
13+
elif component.get('type') == 'view_submission':
14+
view = component.get('view', {})
15+
return view.get('callback_id')
1316
else:
1417
return component.get('callback_id')
1518

tests/data/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,7 @@
99

1010
def get_mock_data(filepath: str):
1111
return open(path.join(MOCK_DIR, filepath))
12+
13+
14+
def test_handler(container):
15+
return "{\"foo\": \"bar\"}"

tests/integration/routes/test_interactive.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,3 +170,21 @@ def test_invalid_callback_id(
170170
)
171171
queue.assert_not_called()
172172
slack_api_call.assert_not_called()
173+
174+
175+
def test_view_submission_synchronous(
176+
client: Client, queue: MagicMock, slack_api_call: MagicMock, mocker
177+
):
178+
mocker.patch("omnibot.services.slack.get_user", return_value={"id": "TEST_USER_ID"})
179+
with get_mock_data("interactive/view_submission_synchronous_test.json") as json_data:
180+
event: Dict[str, Any] = json.loads(json_data.read())
181+
resp: Response = client.post(
182+
_ENDPOINT,
183+
data=event,
184+
content_type="application/x-www-form-urlencoded",
185+
)
186+
component = json.loads(event["payload"])
187+
component["omnibot_bot_id"] = "TEST_OMNIBOT_ID"
188+
queue.assert_not_called()
189+
assert resp.status_code == 200
190+
assert resp.data == b"{\"foo\": \"bar\"}"

0 commit comments

Comments
 (0)