diff options
author | Trygve Aaberge <trygveaa@gmail.com> | 2024-01-07 15:51:33 +0100 |
---|---|---|
committer | Trygve Aaberge <trygveaa@gmail.com> | 2024-02-18 11:32:54 +0100 |
commit | a46a81e29e2eb6df2e77f3fae13ffad690688e88 (patch) | |
tree | e14b90089ab128180b65381b28936d087aed37cc | |
parent | 07a14fdc3a6476b65e3d19f79c20769f80fb5d31 (diff) | |
download | wee-slack-a46a81e29e2eb6df2e77f3fae13ffad690688e88.tar.gz |
Only open channels for the current sub workspace
It's possible to have a token that's only for one workspace in an
enterprise grid. For me with such a token, it returns channels in all
workspaces in client.userBoot, but only channels in the tokens workspace
in client.counts. This meant that we didn't get last_read for all
channels we opened, and additionally some methods like
conversations.members would fail with "channel_not_found" for those
channels.
This filters the channels from client.userBoot by checking that the
channel is in the current sub workspace, if the token we're using is not
an org level (for all workspaces the user is in) token.
Additionally it raises an error if any of the channels to open isn't
included in the response from client.counts to prevent missing last_read
for any channels if there are other channels that isn't included. I
could have filtered the list of channels to open by the channels
included from client.counts, but I don't want any channels to just
silently be ignored.
-rw-r--r-- | slack/slack_api.py | 8 | ||||
-rw-r--r-- | slack/slack_workspace.py | 24 | ||||
-rw-r--r-- | typings/slack_api/slack_team_info.pyi | 43 |
3 files changed, 74 insertions, 1 deletions
diff --git a/slack/slack_api.py b/slack/slack_api.py index 76d97cb..2f57e61 100644 --- a/slack/slack_api.py +++ b/slack/slack_api.py @@ -23,6 +23,7 @@ if TYPE_CHECKING: from slack_api.slack_conversations_replies import SlackConversationsRepliesResponse from slack_api.slack_emoji import SlackEmojiListResponse from slack_api.slack_rtm_connect import SlackRtmConnectResponse + from slack_api.slack_team_info import SlackTeamInfoResponse from slack_api.slack_usergroups_info import SlackUsergroupsInfoResponse from slack_api.slack_users_conversations import SlackUsersConversationsResponse from slack_api.slack_users_info import SlackUserInfoResponse, SlackUsersInfoResponse @@ -129,6 +130,13 @@ class SlackApi(SlackApiCommon): return response return response + async def fetch_team_info(self): + method = "team.info" + response: SlackTeamInfoResponse = await self._fetch(method) + if response["ok"] is False: + raise SlackApiError(self.workspace, method, response) + return response + async def fetch_rtm_connect(self): method = "rtm.connect" response: SlackRtmConnectResponse = await self._fetch(method) diff --git a/slack/slack_workspace.py b/slack/slack_workspace.py index c0652fb..bc1d309 100644 --- a/slack/slack_workspace.py +++ b/slack/slack_workspace.py @@ -233,6 +233,10 @@ class SlackWorkspace: return "unknown" @property + def team_is_org_level(self) -> bool: + return self.id.startswith("E") + + @property def is_connected(self): return self._is_connected @@ -279,12 +283,14 @@ class SlackWorkspace: return conversations_to_open async def _connect_session(self) -> List[SlackConversation]: + team_info_task = create_task(self.api.fetch_team_info()) user_boot_task = create_task(self.api.fetch_client_userboot()) client_counts_task = create_task(self.api.fetch_client_counts()) + team_info = await team_info_task user_boot = await user_boot_task client_counts = await client_counts_task - self.id = user_boot["team"]["id"] + self.id = team_info["team"]["id"] my_user_id = user_boot["self"]["id"] # self.users.initialize_items(my_user_id, {my_user_id: user_boot["self"]}) self.my_user = await self.users[my_user_id] @@ -303,11 +309,27 @@ class SlackWorkspace: channel["id"] for channel in user_boot["channels"] if not channel["is_mpim"] + and ( + self.team_is_org_level + or "internal_team_ids" not in channel + or self.id in channel["internal_team_ids"] + ) ] + user_boot["is_open"] + [count["id"] for count in conversation_counts if count["has_unreads"]] ) + conversation_counts_ids = set(count["id"] for count in conversation_counts) + if not conversation_ids.issubset(conversation_counts_ids): + raise SlackError( + self, + "Unexpectedly missing some conversations in client.counts", + { + "conversation_ids": list(conversation_ids), + "conversation_counts_ids": list(conversation_counts_ids), + }, + ) + channel_infos: Dict[str, SlackConversationsInfoInternal] = { channel["id"]: channel for channel in user_boot["channels"] } diff --git a/typings/slack_api/slack_team_info.pyi b/typings/slack_api/slack_team_info.pyi new file mode 100644 index 0000000..124eaac --- /dev/null +++ b/typings/slack_api/slack_team_info.pyi @@ -0,0 +1,43 @@ +from __future__ import annotations + +from slack_api.slack_common import SlackErrorResponse +from typing_extensions import Literal, NotRequired, TypedDict, final + +@final +class SlackTeamInfoIcon(TypedDict): + image_default: bool + image_34: str + image_44: str + image_68: str + image_88: str + image_102: str + image_230: str + image_132: str + +@final +class SlackTeamInfo(TypedDict): + id: str + name: str + url: str + domain: str + email_domain: str + icon: SlackTeamInfoIcon + avatar_base_url: str + is_verified: bool + + # For enterprise grid + public_url: NotRequired[str] + discoverable: NotRequired[str] + # sso_provider + # pay_prod_cur + locale: NotRequired[str] + enterprise_id: NotRequired[str] + enterprise_name: NotRequired[str] + enterprise_domain: NotRequired[str] + +@final +class SlackTeamInfoSuccessResponse(TypedDict): + ok: Literal[True] + team: SlackTeamInfo + +SlackTeamInfoResponse = SlackTeamInfoSuccessResponse | SlackErrorResponse |