Skip to content

Commit

Permalink
Fix #260 Enable to use respond utility in app.view listeners (only wh…
Browse files Browse the repository at this point in the history
…en response_urls exists)
  • Loading branch information
seratch committed Apr 10, 2021
1 parent b594174 commit b71e9e3
Show file tree
Hide file tree
Showing 5 changed files with 323 additions and 149 deletions.
23 changes: 16 additions & 7 deletions slack_bolt/request/async_internals.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,34 @@
extract_team_id,
extract_user_id,
extract_channel_id,
debug_multiple_response_urls_detected,
)


def build_async_context(
context: AsyncBoltContext,
payload: Dict[str, Any],
body: Dict[str, Any],
) -> AsyncBoltContext:
enterprise_id = extract_enterprise_id(payload)
enterprise_id = extract_enterprise_id(body)
if enterprise_id:
context["enterprise_id"] = enterprise_id
team_id = extract_team_id(payload)
team_id = extract_team_id(body)
if team_id:
context["team_id"] = team_id
user_id = extract_user_id(payload)
user_id = extract_user_id(body)
if user_id:
context["user_id"] = user_id
channel_id = extract_channel_id(payload)
channel_id = extract_channel_id(body)
if channel_id:
context["channel_id"] = channel_id
if "response_url" in payload:
context["response_url"] = payload["response_url"]
if "response_url" in body:
context["response_url"] = body["response_url"]
elif "response_urls" in body:
# In the case where response_url_enabled: true in a modal exists
response_urls = body["response_urls"]
if len(response_urls) >= 1:
if len(response_urls) > 1:
context.logger.debug(debug_multiple_response_urls_detected())
response_url = response_urls[0].get("response_url")
context["response_url"] = response_url
return context
16 changes: 16 additions & 0 deletions slack_bolt/request/internals.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,14 @@ def build_context(context: BoltContext, body: Dict[str, Any]) -> BoltContext:
context["channel_id"] = channel_id
if "response_url" in body:
context["response_url"] = body["response_url"]
elif "response_urls" in body:
# In the case where response_url_enabled: true in a modal exists
response_urls = body["response_urls"]
if len(response_urls) >= 1:
if len(response_urls) > 1:
context.logger.debug(debug_multiple_response_urls_detected())
response_url = response_urls[0].get("response_url")
context["response_url"] = response_url
return context


Expand Down Expand Up @@ -177,3 +185,11 @@ def error_message_raw_body_required_in_http_mode() -> str:

def error_message_unknown_request_body_type() -> str:
return "`body` must be either str or dict"


def debug_multiple_response_urls_detected() -> str:
return (
"`response_urls` in the body has multiple URLs in it. "
"If you would like to use non-primary one, "
"please manually extract the one from body['response_urls']."
)
6 changes: 6 additions & 0 deletions tests/mock_web_api_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,12 @@ def set_common_headers(self):
def _handle(self):
self.received_requests[self.path] = self.received_requests.get(self.path, 0) + 1
try:
if self.path == "/webhook":
self.send_response(200)
self.set_common_headers()
self.wfile.write("OK".encode("utf-8"))
return

if self.path == "/received_requests.json":
self.send_response(200)
self.set_common_headers()
Expand Down
217 changes: 142 additions & 75 deletions tests/scenario_tests/test_view_submission.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,133 @@
from tests.utils import remove_os_env_temporarily, restore_os_env


body = {
"type": "view_submission",
"team": {
"id": "T111",
"domain": "workspace-domain",
"enterprise_id": "E111",
"enterprise_name": "Sandbox Org",
},
"user": {
"id": "W111",
"username": "primary-owner",
"name": "primary-owner",
"team_id": "T111",
},
"api_app_id": "A111",
"token": "verification_token",
"trigger_id": "111.222.valid",
"view": {
"id": "V111",
"team_id": "T111",
"type": "modal",
"blocks": [
{
"type": "input",
"block_id": "hspI",
"label": {
"type": "plain_text",
"text": "Label",
},
"optional": False,
"element": {"type": "plain_text_input", "action_id": "maBWU"},
}
],
"private_metadata": "This is for you!",
"callback_id": "view-id",
"state": {
"values": {"hspI": {"maBWU": {"type": "plain_text_input", "value": "test"}}}
},
"hash": "1596530361.3wRYuk3R",
"title": {
"type": "plain_text",
"text": "My App",
},
"clear_on_close": False,
"notify_on_close": False,
"close": {
"type": "plain_text",
"text": "Cancel",
},
"submit": {
"type": "plain_text",
"text": "Submit",
},
"previous_view_id": None,
"root_view_id": "V111",
"app_id": "A111",
"external_id": "",
"app_installed_team_id": "T111",
"bot_id": "B111",
},
"response_urls": [],
}

raw_body = f"payload={quote(json.dumps(body))}"


def simple_listener(ack, body, payload, view):
assert body["trigger_id"] == "111.222.valid"
assert body["view"] == payload
assert payload == view
assert view["private_metadata"] == "This is for you!"
ack()


response_url_payload_body = {
"type": "view_submission",
"team": {"id": "T111", "domain": "test-test-test"},
"user": {
"id": "U111",
"username": "test-test-test",
"name": "test-test-test",
"team_id": "T111",
},
"api_app_id": "A111",
"token": "verification-token",
"trigger_id": "111.222.xxx",
"view": {
"id": "V111",
"team_id": "T111",
"type": "modal",
"blocks": [],
"callback_id": "view-id",
"state": {},
"title": {
"type": "plain_text",
"text": "My App",
},
"close": {
"type": "plain_text",
"text": "Cancel",
},
"submit": {
"type": "plain_text",
"text": "Submit",
},
"previous_view_id": None,
"root_view_id": "V111",
"app_id": "A111",
"external_id": "",
"app_installed_team_id": "T111",
"bot_id": "B111",
},
"response_urls": [
{
"block_id": "b",
"action_id": "a",
"channel_id": "C111",
"response_url": "http://localhost:8888/webhook",
}
],
"is_enterprise_install": False,
}


raw_response_url_body = f"payload={quote(json.dumps(response_url_payload_body))}"


class TestViewSubmission:
signing_secret = "secret"
valid_token = "xoxb-valid"
Expand Down Expand Up @@ -46,11 +173,9 @@ def build_headers(self, timestamp: str, body: str):
"x-slack-request-timestamp": [timestamp],
}

def build_valid_request(self) -> BoltRequest:
def build_valid_request(self, body: str = raw_body) -> BoltRequest:
timestamp = str(int(time()))
return BoltRequest(
body=raw_body, headers=self.build_headers(timestamp, raw_body)
)
return BoltRequest(body=body, headers=self.build_headers(timestamp, body))

def test_mock_server_is_running(self):
resp = self.web_client.api_test()
Expand Down Expand Up @@ -123,76 +248,18 @@ def test_failure_2(self):
assert response.status == 404
assert_auth_test_count(self, 1)

def test_response_urls(self):
app = App(
client=self.web_client,
signing_secret=self.signing_secret,
)

body = {
"type": "view_submission",
"team": {
"id": "T111",
"domain": "workspace-domain",
"enterprise_id": "E111",
"enterprise_name": "Sandbox Org",
},
"user": {
"id": "W111",
"username": "primary-owner",
"name": "primary-owner",
"team_id": "T111",
},
"api_app_id": "A111",
"token": "verification_token",
"trigger_id": "111.222.valid",
"view": {
"id": "V111",
"team_id": "T111",
"type": "modal",
"blocks": [
{
"type": "input",
"block_id": "hspI",
"label": {
"type": "plain_text",
"text": "Label",
},
"optional": False,
"element": {"type": "plain_text_input", "action_id": "maBWU"},
}
],
"private_metadata": "This is for you!",
"callback_id": "view-id",
"state": {
"values": {"hspI": {"maBWU": {"type": "plain_text_input", "value": "test"}}}
},
"hash": "1596530361.3wRYuk3R",
"title": {
"type": "plain_text",
"text": "My App",
},
"clear_on_close": False,
"notify_on_close": False,
"close": {
"type": "plain_text",
"text": "Cancel",
},
"submit": {
"type": "plain_text",
"text": "Submit",
},
"previous_view_id": None,
"root_view_id": "V111",
"app_id": "A111",
"external_id": "",
"app_installed_team_id": "T111",
"bot_id": "B111",
},
"response_urls": [],
}

raw_body = f"payload={quote(json.dumps(body))}"

@app.view("view-id")
def check(ack, respond):
respond("Hi")
ack()

def simple_listener(ack, body, payload, view):
assert body["trigger_id"] == "111.222.valid"
assert body["view"] == payload
assert payload == view
assert view["private_metadata"] == "This is for you!"
ack()
request = self.build_valid_request(raw_response_url_body)
response = app.dispatch(request)
assert response.status == 200
assert_auth_test_count(self, 1)
Loading

0 comments on commit b71e9e3

Please sign in to comment.