diff --git a/libraries/botbuilder-adapters-slack/botbuilder/adapters/slack/slack_action.py b/libraries/botbuilder-adapters-slack/botbuilder/adapters/slack/slack_action.py new file mode 100644 index 000000000..e3482a560 --- /dev/null +++ b/libraries/botbuilder-adapters-slack/botbuilder/adapters/slack/slack_action.py @@ -0,0 +1,15 @@ +from typing import Optional +from botbuilder.adapters.slack.slack_text import SlackText + + +# Slack action block (https://api.slack.com/reference/block-kit/block-elements) +class SlackAction: + def __init__(self, **kwargs): + self.action_id: str = kwargs.get("action_id") + self.block_id: str = kwargs.get("block_id") + self.value: str = kwargs.get("value") + self.type: str = kwargs.get("type") + self.action_ts: str = kwargs.get("action_ts") + self.text: Optional[SlackText] = ( + None if "text" not in kwargs else SlackText(**(kwargs.get("text"))) + ) diff --git a/libraries/botbuilder-adapters-slack/botbuilder/adapters/slack/slack_event.py b/libraries/botbuilder-adapters-slack/botbuilder/adapters/slack/slack_event.py index 66b810ffb..e48774709 100644 --- a/libraries/botbuilder-adapters-slack/botbuilder/adapters/slack/slack_event.py +++ b/libraries/botbuilder-adapters-slack/botbuilder/adapters/slack/slack_event.py @@ -1,7 +1,8 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. -from typing import List +from typing import Optional, List +from botbuilder.adapters.slack.slack_action import SlackAction from botbuilder.adapters.slack.slack_message import SlackMessage @@ -25,10 +26,13 @@ def __init__(self, **kwargs): self.user = kwargs.get("user") self.user_id = kwargs.get("user_id") self.bot_id = kwargs.get("bot_id") - self.actions: List[str] = kwargs.get("actions") + self.actions: Optional[List[SlackAction]] = None self.item = kwargs.get("item") self.item_channel = kwargs.get("item_channel") self.files: [] = kwargs.get("files") self.message = ( None if "message" not in kwargs else SlackMessage(**kwargs.get("message")) ) + + if "actions" in kwargs: + self.actions = [SlackAction(**action) for action in kwargs.get("actions")] diff --git a/libraries/botbuilder-adapters-slack/botbuilder/adapters/slack/slack_helper.py b/libraries/botbuilder-adapters-slack/botbuilder/adapters/slack/slack_helper.py index d71fd7852..68dc9ab25 100644 --- a/libraries/botbuilder-adapters-slack/botbuilder/adapters/slack/slack_helper.py +++ b/libraries/botbuilder-adapters-slack/botbuilder/adapters/slack/slack_helper.py @@ -3,6 +3,7 @@ import json import urllib.parse +from datetime import datetime, timezone from aiohttp.web_request import Request from aiohttp.web_response import Response @@ -54,9 +55,31 @@ def activity_to_slack(activity: Activity) -> SlackMessage: for att in activity.attachments: if att.name == "blocks": message.blocks = att.content + + elif att.content_type == "application/vnd.microsoft.card.hero": + message.blocks = [ + { + "type": "section", + "text": {"type": "mrkdwn", "text": att.content.text}, + }, + { + "type": "actions", + "elements": [ + { + "type": "button", + "text": {"type": "plain_text", "text": i.title}, + "value": i.value, + } + for i in att.content.buttons + ], + }, + ] + else: new_attachment = Attachment( - author_name=att.name, thumb_url=att.thumbnail_url, text="", + author_name=att.name, + thumb_url=att.thumbnail_url, + text="", ) attachments.append(new_attachment) @@ -124,9 +147,13 @@ def payload_to_activity(payload: SlackPayload) -> Activity: activity = Activity( channel_id="slack", - conversation=ConversationAccount(id=payload.channel.id, properties={}), + conversation=ConversationAccount( + id=payload.channel.get("id"), properties={} + ), from_property=ChannelAccount( - id=payload.message.bot_id if payload.message.bot_id else payload.user.id + id=payload.message.bot_id + if payload.message.bot_id + else payload.user.get("id") ), recipient=ChannelAccount(), channel_data=payload, @@ -141,7 +168,7 @@ def payload_to_activity(payload: SlackPayload) -> Activity: payload.type == "block_actions" or payload.type == "interactive_message" ): activity.type = ActivityTypes.message - activity.text = payload.actions.value + activity.text = payload.actions[0].value return activity @@ -168,12 +195,17 @@ async def event_to_activity(event: SlackEvent, client: SlackClient) -> Activity: id=event.channel if event.channel else event.channel_id, properties={} ), from_property=ChannelAccount( - id=event.bot_id if event.bot_id else event.user_id + id=event.bot_id + if event.bot_id + else event.user_id + if event.user_id + else event.user ), recipient=ChannelAccount(id=None), channel_data=event, text=event.text, type=ActivityTypes.event, + timestamp=datetime.fromtimestamp(float(event.event_ts), tz=timezone.utc), ) if event.thread_ts: @@ -254,7 +286,7 @@ def query_string_to_dictionary(query: str) -> {}: for pair in pairs: key_value = pair.split("=") key = key_value[0] - value = urllib.parse.unquote(key_value[1]) + value = json.loads(urllib.parse.unquote(key_value[1])) values[key] = value @@ -287,7 +319,7 @@ def deserialize_body(content_type: str, request_body: str) -> SlackRequestBody: return SlackRequestBody(**request_dict) if "payload=" in request_body: - payload = SlackPayload(**request_dict) + payload = SlackPayload(**(request_dict.get("payload"))) return SlackRequestBody(payload=payload, token=payload.token) return SlackRequestBody(**request_dict) diff --git a/libraries/botbuilder-adapters-slack/botbuilder/adapters/slack/slack_payload.py b/libraries/botbuilder-adapters-slack/botbuilder/adapters/slack/slack_payload.py index 9b7438619..5aeb0e380 100644 --- a/libraries/botbuilder-adapters-slack/botbuilder/adapters/slack/slack_payload.py +++ b/libraries/botbuilder-adapters-slack/botbuilder/adapters/slack/slack_payload.py @@ -2,19 +2,19 @@ # Licensed under the MIT License. from typing import Optional, List -from slack.web.classes.actions import Action +from botbuilder.adapters.slack.slack_action import SlackAction from botbuilder.adapters.slack.slack_message import SlackMessage class SlackPayload: def __init__(self, **kwargs): - self.type: List[str] = kwargs.get("type") + self.type: [str] = kwargs.get("type") self.token: str = kwargs.get("token") self.channel: str = kwargs.get("channel") self.thread_ts: str = kwargs.get("thread_ts") self.team: str = kwargs.get("team") self.user: str = kwargs.get("user") - self.actions: Optional[List[Action]] = None + self.actions: Optional[List[SlackAction]] = None self.trigger_id: str = kwargs.get("trigger_id") self.action_ts: str = kwargs.get("action_ts") self.submission: str = kwargs.get("submission") @@ -26,6 +26,9 @@ def __init__(self, **kwargs): message = kwargs.get("message") self.message = ( message - if isinstance(message) is SlackMessage + if isinstance(message, SlackMessage) else SlackMessage(**message) ) + + if "actions" in kwargs: + self.actions = [SlackAction(**action) for action in kwargs.get("actions")] diff --git a/libraries/botbuilder-adapters-slack/botbuilder/adapters/slack/slack_text.py b/libraries/botbuilder-adapters-slack/botbuilder/adapters/slack/slack_text.py new file mode 100644 index 000000000..0dc39e507 --- /dev/null +++ b/libraries/botbuilder-adapters-slack/botbuilder/adapters/slack/slack_text.py @@ -0,0 +1,7 @@ +# Slack text object (https://api.slack.com/reference/block-kit/composition-objects#text) +class SlackText: + def __init__(self, **kwargs): + self.text: str = kwargs.get("text") + self.type: str = kwargs.get("type") + self.emoji: bool = kwargs.get("emoji") + self.verbatim: bool = kwargs.get("varbatim")