diff options
author | Trygve Aaberge <trygveaa@gmail.com> | 2024-01-18 22:45:03 +0100 |
---|---|---|
committer | Trygve Aaberge <trygveaa@gmail.com> | 2024-02-18 12:56:59 +0100 |
commit | 15cabf8ba1b9daa7e28475ea46cc5a8fd478e174 (patch) | |
tree | f65e557a115b0f83d13cb6d4b9943ddbd273268c /slack | |
parent | bb80ee68763233930a6f4169b07a029cd99b589d (diff) | |
download | wee-slack-15cabf8ba1b9daa7e28475ea46cc5a8fd478e174.tar.gz |
Support files in Slack Connect channels
Files uploaded in Slack Connect channels doesn't contain any
information, so we have to make a request to files.info in order to get
the information to render it.
See https://api.slack.com/apis/channels-between-orgs#check_file_info for
more info.
Diffstat (limited to 'slack')
-rw-r--r-- | slack/slack_api.py | 9 | ||||
-rw-r--r-- | slack/slack_message.py | 110 |
2 files changed, 71 insertions, 48 deletions
diff --git a/slack/slack_api.py b/slack/slack_api.py index c54268f..1faf4a2 100644 --- a/slack/slack_api.py +++ b/slack/slack_api.py @@ -29,6 +29,7 @@ if TYPE_CHECKING: from slack_api.slack_conversations_members import SlackConversationsMembersResponse from slack_api.slack_conversations_replies import SlackConversationsRepliesResponse from slack_api.slack_emoji import SlackEmojiListResponse + from slack_api.slack_files_info import SlackFilesInfoResponse from slack_api.slack_profile import SlackSetProfile, SlackUsersProfileSetResponse from slack_api.slack_rtm_connect import SlackRtmConnectResponse from slack_api.slack_team_info import SlackTeamInfoResponse @@ -321,6 +322,14 @@ class SlackApi(SlackApiCommon): raise SlackApiError(self.workspace, method, response) return response + async def fetch_files_info(self, file_id: str): + method = "files.info" + params: Params = {"file": file_id} + response: SlackFilesInfoResponse = await self._fetch(method, params) + if response["ok"] is False: + raise SlackApiError(self.workspace, method, response) + return response + async def fetch_emoji_list(self): method = "emoji.list" response: SlackEmojiListResponse = await self._fetch(method) diff --git a/slack/slack_message.py b/slack/slack_message.py index 3e1ea20..576629c 100644 --- a/slack/slack_message.py +++ b/slack/slack_message.py @@ -38,10 +38,10 @@ if TYPE_CHECKING: SlackMessageBlockRichTextElement, SlackMessageBlockRichTextList, SlackMessageBlockRichTextSection, - SlackMessageFile, SlackMessageReaction, SlackMessageSubtypeHuddleThreadRoom, ) + from slack_api.slack_files_info import SlackFile from slack_rtm.slack_rtm_message import SlackThreadSubscription from typing_extensions import Literal, assert_never @@ -184,19 +184,21 @@ class PendingMessageItem: self, message: SlackMessage, item_type: Literal[ - "conversation", "user", "usergroup", "broadcast", "message_nick" + "conversation", "user", "usergroup", "broadcast", "message_nick", "file" ], item_id: str, display_type: Literal["mention", "chat"] = "mention", fallback_name: Optional[str] = None, + file: Optional[SlackFile] = None, ): self.message = message self.item_type: Literal[ - "conversation", "user", "usergroup", "broadcast", "message_nick" + "conversation", "user", "usergroup", "broadcast", "message_nick", "file" ] = item_type self.item_id = item_id self.display_type: Literal["mention", "chat"] = display_type self.fallback_name = fallback_name + self.file = file def __repr__(self): return f"{self.__class__.__name__}({self.message}, {self.item_type}, {self.item_id}, {self.display_type})" @@ -284,6 +286,49 @@ class PendingMessageItem: nick = await self.message.nick() return nick.format(colorize=True) + elif self.item_type == "file": + if self.file is None or self.file.get("file_access") == "check_file_info": + file_response = await self.message.workspace.api.fetch_files_info( + self.item_id + ) + file = file_response["file"] + else: + file = self.file + + if file.get("mode") == "tombstone": + return with_color( + shared.config.color.deleted_message.value, + "(This file was deleted)", + ) + elif file.get("mode") == "hidden_by_limit": + return with_color( + shared.config.color.deleted_message.value, + "(This file is not available because the workspace has passed its storage limit)", + ) + elif file.get("file_access") == "file_not_found": + return with_color( + shared.config.color.deleted_message.value, + "(This file was not found)", + ) + elif ( + file.get("mimetype") == "application/vnd.slack-docs" + and "permalink" in file + ): + url = f"{file['permalink']}?origin_team={self.message.workspace.id}&origin_channel={self.message.conversation.id}" + title = unhtmlescape(file.get("title", "")) + return format_url(url, title) + elif "url_private" in file: + title = unhtmlescape(file.get("title", "")) + return format_url(file["url_private"], title) + else: + error = SlackError(self.message.workspace, "Unsupported file", file) + uncaught_error = UncaughtError(error) + store_uncaught_error(uncaught_error) + return with_color( + shared.config.color.render_error.value, + f"<Unsupported file, error id: {uncaught_error.id}>", + ) + else: assert_never(self.item_type) @@ -300,6 +345,8 @@ class PendingMessageItem: return not only_personal elif self.item_type == "message_nick": return False + elif self.item_type == "file": + return False else: assert_never(self.item_type) @@ -686,12 +733,9 @@ class SlackMessage: for item in items ] - files_text = self._render_files(self._message_json.get("files", [])) - if files_text: - texts.extend(["\n", files_text]) - + files = self._render_files(self._message_json.get("files", []), bool(texts)) attachment_items = self._render_attachments(texts) - self._parsed_message = texts + attachment_items + self._parsed_message = texts + files + attachment_items return self._parsed_message @@ -1107,44 +1151,14 @@ class SlackMessage: else: return "▪︎" - def _render_files(self, files: List[SlackMessageFile]) -> str: - lines: List[str] = [] - for file in files: - if file.get("mode") == "tombstone": - text = with_color( - shared.config.color.deleted_message.value, "(This file was deleted)" - ) - elif file.get("mode") == "hidden_by_limit": - text = with_color( - shared.config.color.deleted_message.value, - "(This file is not available because the workspace has passed its storage limit)", - ) - if file.get("file_access") == "file_not_found": - text = with_color( - shared.config.color.deleted_message.value, - "(This file was not found)", - ) - elif ( - file.get("mimetype") == "application/vnd.slack-docs" - and "permalink" in file - ): - url = f"{file['permalink']}?origin_team={self.workspace.id}&origin_channel={self.conversation.id}" - title = unhtmlescape(file.get("title", "")) - text = format_url(url, title) - elif "url_private" in file: - title = unhtmlescape(file.get("title", "")) - text = format_url(file["url_private"], title) - else: - error = SlackError(self.workspace, "Unsupported file", file) - uncaught_error = UncaughtError(error) - store_uncaught_error(uncaught_error) - text = with_color( - shared.config.color.render_error.value, - f"<Unsupported file, error id: {uncaught_error.id}>", - ) - lines.append(text) - - return "\n".join(lines) + def _render_files( + self, files: List[SlackFile], has_items_before: bool + ) -> List[Union[str, PendingMessageItem]]: + items = [ + PendingMessageItem(self, "file", file["id"], file=file) for file in files + ] + before = ["\n"] if has_items_before and items else [] + return before + intersperse(items, "\n") # TODO: Check if mentions in attachments should highlight def _render_attachments( @@ -1232,9 +1246,9 @@ class SlackMessage: [item for item in self._unfurl_and_unescape(line)] for line in lines ] - files = self._render_files(attachment.get("files", [])) + files = self._render_files(attachment.get("files", []), False) if files: - lines.append([files]) + lines.append(files) # TODO: Don't render both text and blocks blocks_items = self._render_blocks(attachment.get("blocks", [])) |