From d417dc95a26c63a82c5ae43197ab17216f29c308 Mon Sep 17 00:00:00 2001 From: Kazuhiro Sera Date: Tue, 15 Nov 2022 15:04:27 +0900 Subject: [PATCH] Fix #1297 Building user_auth_blocks with slack_sdk.models class objects for chat.unfurl API call fails --- slack_sdk/web/async_client.py | 3 ++- slack_sdk/web/client.py | 3 ++- slack_sdk/web/internal_utils.py | 9 +++++---- slack_sdk/web/legacy_client.py | 3 ++- tests/slack_sdk/web/test_internal_utils.py | 12 +++++++++++- tests/slack_sdk/web/test_web_client.py | 11 +++++++++++ .../slack_sdk_async/web/test_async_web_client.py | 15 +++++++++++++-- 7 files changed, 46 insertions(+), 10 deletions(-) diff --git a/slack_sdk/web/async_client.py b/slack_sdk/web/async_client.py index 24f8f7030..3daeb97c7 100644 --- a/slack_sdk/web/async_client.py +++ b/slack_sdk/web/async_client.py @@ -2131,7 +2131,7 @@ async def chat_unfurl( ts: Optional[str] = None, source: Optional[str] = None, unfurl_id: Optional[str] = None, - unfurls: Dict[str, Dict], + unfurls: Optional[Dict[str, Dict]] = None, # or user_auth_* user_auth_blocks: Optional[Union[str, Sequence[Union[Dict, Block]]]] = None, user_auth_message: Optional[str] = None, user_auth_required: Optional[bool] = None, @@ -2154,6 +2154,7 @@ async def chat_unfurl( "user_auth_url": user_auth_url, } ) + _parse_web_class_objects(kwargs) # for user_auth_blocks kwargs = _remove_none_values(kwargs) # NOTE: intentionally using json over params for API methods using blocks/attachments return await self.api_call("chat.unfurl", json=kwargs) diff --git a/slack_sdk/web/client.py b/slack_sdk/web/client.py index 07116d12b..e599aaea9 100644 --- a/slack_sdk/web/client.py +++ b/slack_sdk/web/client.py @@ -2122,7 +2122,7 @@ def chat_unfurl( ts: Optional[str] = None, source: Optional[str] = None, unfurl_id: Optional[str] = None, - unfurls: Dict[str, Dict], + unfurls: Optional[Dict[str, Dict]] = None, # or user_auth_* user_auth_blocks: Optional[Union[str, Sequence[Union[Dict, Block]]]] = None, user_auth_message: Optional[str] = None, user_auth_required: Optional[bool] = None, @@ -2145,6 +2145,7 @@ def chat_unfurl( "user_auth_url": user_auth_url, } ) + _parse_web_class_objects(kwargs) # for user_auth_blocks kwargs = _remove_none_values(kwargs) # NOTE: intentionally using json over params for API methods using blocks/attachments return self.api_call("chat.unfurl", json=kwargs) diff --git a/slack_sdk/web/internal_utils.py b/slack_sdk/web/internal_utils.py index e5acd6f8a..45132d919 100644 --- a/slack_sdk/web/internal_utils.py +++ b/slack_sdk/web/internal_utils.py @@ -194,10 +194,11 @@ def to_dict(obj: Union[Dict, Block, Attachment, Metadata]): return obj.to_dict() return obj - blocks = kwargs.get("blocks", None) - if blocks is not None and isinstance(blocks, Sequence) and (not isinstance(blocks, str)): - dict_blocks = [to_dict(b) for b in blocks] - kwargs.update({"blocks": dict_blocks}) + for blocks_name in ["blocks", "user_auth_blocks"]: + blocks = kwargs.get(blocks_name, None) + if blocks is not None and isinstance(blocks, Sequence) and (not isinstance(blocks, str)): + dict_blocks = [to_dict(b) for b in blocks] + kwargs.update({blocks_name: dict_blocks}) attachments = kwargs.get("attachments", None) if attachments is not None and isinstance(attachments, Sequence) and (not isinstance(attachments, str)): diff --git a/slack_sdk/web/legacy_client.py b/slack_sdk/web/legacy_client.py index f5be528a5..e5fc490af 100644 --- a/slack_sdk/web/legacy_client.py +++ b/slack_sdk/web/legacy_client.py @@ -2133,7 +2133,7 @@ def chat_unfurl( ts: Optional[str] = None, source: Optional[str] = None, unfurl_id: Optional[str] = None, - unfurls: Dict[str, Dict], + unfurls: Optional[Dict[str, Dict]] = None, # or user_auth_* user_auth_blocks: Optional[Union[str, Sequence[Union[Dict, Block]]]] = None, user_auth_message: Optional[str] = None, user_auth_required: Optional[bool] = None, @@ -2156,6 +2156,7 @@ def chat_unfurl( "user_auth_url": user_auth_url, } ) + _parse_web_class_objects(kwargs) # for user_auth_blocks kwargs = _remove_none_values(kwargs) # NOTE: intentionally using json over params for API methods using blocks/attachments return self.api_call("chat.unfurl", json=kwargs) diff --git a/tests/slack_sdk/web/test_internal_utils.py b/tests/slack_sdk/web/test_internal_utils.py index 005681995..a18f81900 100644 --- a/tests/slack_sdk/web/test_internal_utils.py +++ b/tests/slack_sdk/web/test_internal_utils.py @@ -5,7 +5,7 @@ import pytest from slack_sdk.models.attachments import Attachment -from slack_sdk.models.blocks import Block +from slack_sdk.models.blocks import Block, DividerBlock from slack_sdk.web.internal_utils import _build_unexpected_body_error_message, _parse_web_class_objects @@ -62,3 +62,13 @@ def test_can_parse_str_attachments(self): _parse_web_class_objects(kwargs) assert isinstance(kwargs["attachments"], str) assert input == kwargs["attachments"] + + def test_can_parse_user_auth_blocks(self): + kwargs = { + "channel": "C12345", + "ts": "1111.2222", + "unfurls": {}, + "user_auth_blocks": [DividerBlock(), DividerBlock()], + } + _parse_web_class_objects(kwargs) + assert isinstance(kwargs["user_auth_blocks"][0], dict) diff --git a/tests/slack_sdk/web/test_web_client.py b/tests/slack_sdk/web/test_web_client.py index e7eee5a29..579ed2135 100644 --- a/tests/slack_sdk/web/test_web_client.py +++ b/tests/slack_sdk/web/test_web_client.py @@ -5,6 +5,7 @@ import slack_sdk.errors as err from slack_sdk import WebClient +from slack_sdk.models.blocks import DividerBlock from slack_sdk.models.metadata import Metadata from tests.slack_sdk.web.mock_web_api_server import ( setup_mock_web_api_server, @@ -218,3 +219,13 @@ def test_message_metadata(self): ), ) self.assertIsNone(scheduled.get("error")) + + def test_user_auth_blocks(self): + client = self.client + new_message = client.chat_unfurl( + channel="C12345", + ts="1111.2222", + unfurls={}, + user_auth_blocks=[DividerBlock(), DividerBlock()], + ) + self.assertIsNone(new_message.get("error")) diff --git a/tests/slack_sdk_async/web/test_async_web_client.py b/tests/slack_sdk_async/web/test_async_web_client.py index 236f3e9f6..53ccb1b76 100644 --- a/tests/slack_sdk_async/web/test_async_web_client.py +++ b/tests/slack_sdk_async/web/test_async_web_client.py @@ -1,9 +1,8 @@ import re import unittest -import aiohttp - import slack_sdk.errors as err +from slack_sdk.models.blocks import DividerBlock from slack_sdk.web.async_client import AsyncWebClient from tests.slack_sdk_async.helpers import async_test from tests.slack_sdk.web.mock_web_api_server import ( @@ -153,3 +152,15 @@ async def test_default_team_id(self): client = AsyncWebClient(base_url="http://localhost:8888", team_id="T_DEFAULT") resp = await client.users_list(token="xoxb-users_list_pagination") self.assertIsNone(resp["error"]) + + @async_test + async def test_user_auth_blocks(self): + self.client.token = "xoxb-api_test" + client = self.client + new_message = await client.chat_unfurl( + channel="C12345", + ts="1111.2222", + unfurls={}, + user_auth_blocks=[DividerBlock(), DividerBlock()], + ) + self.assertIsNone(new_message.get("error"))