Skip to content

Commit 1f252e0

Browse files
author
Kian Attari
authored
Issue-729 admin conversations restrict access API (#754)
1 parent 47876ab commit 1f252e0

File tree

4 files changed

+162
-3
lines changed

4 files changed

+162
-3
lines changed
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import asyncio
2+
import logging
3+
import os
4+
import time
5+
import unittest
6+
7+
from integration_tests.env_variable_names import SLACK_SDK_TEST_GRID_WORKSPACE_ADMIN_USER_TOKEN, \
8+
SLACK_SDK_TEST_GRID_ORG_ADMIN_USER_TOKEN, \
9+
SLACK_SDK_TEST_GRID_IDP_USERGROUP_ID, SLACK_SDK_TEST_GRID_TEAM_ID
10+
from integration_tests.helpers import async_test
11+
from slack import WebClient
12+
13+
14+
class TestWebClient(unittest.TestCase):
15+
"""Runs integration tests with real Slack API"""
16+
17+
def setUp(self):
18+
self.logger = logging.getLogger(__name__)
19+
self.org_admin_token = os.environ[SLACK_SDK_TEST_GRID_ORG_ADMIN_USER_TOKEN]
20+
self.sync_client: WebClient = WebClient(
21+
token=self.org_admin_token,
22+
run_async=False,
23+
loop=asyncio.new_event_loop()
24+
)
25+
self.async_client: WebClient = WebClient(token=self.org_admin_token, run_async=True)
26+
27+
self.team_id = os.environ[SLACK_SDK_TEST_GRID_TEAM_ID]
28+
self.idp_group_id = os.environ[SLACK_SDK_TEST_GRID_IDP_USERGROUP_ID]
29+
30+
if not hasattr(self, "channel_id"):
31+
team_admin_token = os.environ[SLACK_SDK_TEST_GRID_WORKSPACE_ADMIN_USER_TOKEN]
32+
client = WebClient(token=team_admin_token)
33+
# Only fetching private channels since admin.conversations.restrictAccess methods do not work for public channels
34+
convs = client.conversations_list(exclude_archived=True, limit=100, types="private_channel")
35+
self.channel_id = next((c["id"] for c in convs["channels"] if c["name"] != "general"), None)
36+
if self.channel_id is None:
37+
millis = int(round(time.time() * 1000))
38+
channel_name = f"private-test-channel-{millis}"
39+
self.channel_id = client.conversations_create(
40+
name=channel_name,
41+
is_private=True,
42+
)["channel"]["id"]
43+
44+
def tearDown(self):
45+
pass
46+
47+
def test_sync(self):
48+
client = self.sync_client
49+
50+
add_group = client.admin_conversations_restrictAccess_addGroup(
51+
channel_id=self.channel_id,
52+
group_id=self.idp_group_id,
53+
team_id=self.team_id
54+
)
55+
self.assertIsNotNone(add_group)
56+
# To avoid rate limiting errors
57+
time.sleep(10)
58+
59+
list_groups = client.admin_conversations_restrictAccess_listGroups(
60+
team_id=self.team_id,
61+
channel_id=self.channel_id
62+
)
63+
self.assertIsNotNone(list_groups)
64+
# To avoid rate limiting errors
65+
time.sleep(10)
66+
67+
remove_group = client.admin_conversations_restrictAccess_removeGroup(
68+
channel_id=self.channel_id,
69+
group_id=self.idp_group_id,
70+
team_id=self.team_id
71+
)
72+
self.assertIsNotNone(remove_group)
73+
# To avoid rate limiting errors
74+
time.sleep(20)
75+
76+
@async_test
77+
async def test_async(self):
78+
client = self.async_client
79+
80+
add_group = await client.admin_conversations_restrictAccess_addGroup(
81+
channel_id=self.channel_id,
82+
group_id=self.idp_group_id,
83+
team_id=self.team_id
84+
)
85+
self.assertIsNotNone(add_group)
86+
# To avoid rate limiting errors
87+
await asyncio.sleep(10)
88+
89+
list_groups = await client.admin_conversations_restrictAccess_listGroups(
90+
team_id=self.team_id,
91+
channel_id=self.channel_id
92+
)
93+
self.assertIsNotNone(list_groups)
94+
# To avoid rate limiting errors
95+
await asyncio.sleep(10)
96+
97+
remove_group = await client.admin_conversations_restrictAccess_removeGroup(
98+
channel_id=self.channel_id,
99+
group_id=self.idp_group_id,
100+
team_id=self.team_id
101+
)
102+
self.assertIsNotNone(remove_group)
103+
# To avoid rate limiting errors
104+
await asyncio.sleep(20)

slack/web/base_client.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -686,7 +686,13 @@ def _update_call_participants(kwargs, users: Union[str, List[Dict[str, str]]]):
686686

687687

688688
# https://api.slack.com/changelog/2020-01-deprecating-antecedents-to-the-conversations-api
689-
deprecated_method_prefixes_2020_01 = ["channels.", "groups.", "im.", "mpim."]
689+
deprecated_method_prefixes_2020_01 = [
690+
"channels.",
691+
"groups.",
692+
"im.",
693+
"mpim.",
694+
"admin.conversations.whitelist.",
695+
]
690696

691697

692698
def show_2020_01_deprecation(method_name: str):

slack/web/client.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,36 @@ def admin_apps_restricted_list(self, **kwargs) -> Union[Future, SlackResponse]:
109109
"admin.apps.restricted.list", http_verb="GET", params=kwargs
110110
)
111111

112+
def admin_conversations_restrictAccess_addGroup(
113+
self, **kwargs
114+
) -> Union[Future, SlackResponse]:
115+
"""Add an allowlist of IDP groups for accessing a channel."""
116+
return self.api_call(
117+
"admin.conversations.restrictAccess.addGroup",
118+
http_verb="GET",
119+
params=kwargs,
120+
)
121+
122+
def admin_conversations_restrictAccess_listGroups(
123+
self, **kwargs
124+
) -> Union[Future, SlackResponse]:
125+
"""List all IDP Groups linked to a channel."""
126+
return self.api_call(
127+
"admin.conversations.restrictAccess.listGroups",
128+
http_verb="GET",
129+
params=kwargs,
130+
)
131+
132+
def admin_conversations_restrictAccess_removeGroup(
133+
self, **kwargs
134+
) -> Union[Future, SlackResponse]:
135+
"""Remove a linked IDP group linked from a private channel."""
136+
return self.api_call(
137+
"admin.conversations.restrictAccess.removeGroup",
138+
http_verb="GET",
139+
params=kwargs,
140+
)
141+
112142
def admin_conversations_setTeams(self, **kwargs) -> Union[Future, SlackResponse]:
113143
"""Set the workspaces in an Enterprise grid org that connect to a channel."""
114144
return self.api_call("admin.conversations.setTeams", json=kwargs)
@@ -930,6 +960,18 @@ def conversations_list(self, **kwargs) -> Union[Future, SlackResponse]:
930960
"""Lists all channels in a Slack team."""
931961
return self.api_call("conversations.list", http_verb="GET", params=kwargs)
932962

963+
def conversations_mark(
964+
self, *, channel: str, ts: str, **kwargs
965+
) -> Union[Future, SlackResponse]:
966+
"""Sets the read cursor in a channel.
967+
968+
Args:
969+
channel (str): Channel or conversation to set the read cursor for e.g. 'C1234567890'
970+
ts (str): Unique identifier of message to mark as most recently seen in the convo e.g. '1593473566.000200'
971+
"""
972+
kwargs.update({"channel": channel, "ts": ts})
973+
return self.api_call("conversations.mark", json=kwargs)
974+
933975
def conversations_members(
934976
self, *, channel: str, **kwargs
935977
) -> Union[Future, SlackResponse]:

tests/web/test_web_client_coverage.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88

99

1010
class TestWebClientCoverage(unittest.TestCase):
11-
# 196 endpoints as of May 28, 2020
11+
# 205 endpoints as of July 16, 2020
1212
# Can be fetched by running `var methodNames = [].slice.call(document.getElementsByClassName('bold')).map(e => e.text);console.log(methodNames.toString());console.log(methodNames.length);` on https://api.slack.com/methods
13-
all_api_methods = "admin.apps.approve,admin.apps.restrict,admin.apps.approved.list,admin.apps.requests.list,admin.apps.restricted.list,admin.conversations.setTeams,admin.emoji.add,admin.emoji.addAlias,admin.emoji.list,admin.emoji.remove,admin.emoji.rename,admin.inviteRequests.approve,admin.inviteRequests.deny,admin.inviteRequests.list,admin.inviteRequests.approved.list,admin.inviteRequests.denied.list,admin.teams.admins.list,admin.teams.create,admin.teams.list,admin.teams.owners.list,admin.teams.settings.info,admin.teams.settings.setDefaultChannels,admin.teams.settings.setDescription,admin.teams.settings.setDiscoverability,admin.teams.settings.setIcon,admin.teams.settings.setName,admin.usergroups.addChannels,admin.usergroups.listChannels,admin.usergroups.removeChannels,admin.users.assign,admin.users.invite,admin.users.list,admin.users.remove,admin.users.setAdmin,admin.users.setExpiration,admin.users.setOwner,admin.users.setRegular,admin.users.session.reset,api.test,apps.permissions.info,apps.permissions.request,apps.permissions.resources.list,apps.permissions.scopes.list,apps.permissions.users.list,apps.permissions.users.request,apps.uninstall,auth.revoke,auth.test,bots.info,calls.add,calls.end,calls.info,calls.update,calls.participants.add,chat.delete,chat.deleteScheduledMessage,chat.getPermalink,chat.meMessage,chat.postEphemeral,chat.postMessage,chat.scheduleMessage,chat.unfurl,chat.update,chat.scheduledMessages.list,conversations.archive,conversations.close,conversations.create,conversations.history,conversations.info,conversations.invite,conversations.join,conversations.kick,conversations.leave,conversations.list,conversations.members,conversations.open,conversations.rename,conversations.replies,conversations.setPurpose,conversations.setTopic,conversations.unarchive,dialog.open,dnd.endDnd,dnd.endSnooze,dnd.info,dnd.setSnooze,dnd.teamInfo,emoji.list,files.comments.delete,files.delete,files.info,files.list,files.revokePublicURL,files.sharedPublicURL,files.upload,files.remote.add,files.remote.info,files.remote.list,files.remote.remove,files.remote.share,files.remote.update,migration.exchange,oauth.access,oauth.token,oauth.v2.access,pins.add,pins.list,pins.remove,reactions.add,reactions.get,reactions.list,reactions.remove,reminders.add,reminders.complete,reminders.delete,reminders.info,reminders.list,rtm.connect,rtm.start,search.all,search.files,search.messages,stars.add,stars.list,stars.remove,team.accessLogs,team.billableInfo,team.info,team.integrationLogs,team.profile.get,usergroups.create,usergroups.disable,usergroups.enable,usergroups.list,usergroups.update,usergroups.users.list,usergroups.users.update,users.conversations,users.deletePhoto,users.getPresence,users.identity,users.info,users.list,users.lookupByEmail,users.setActive,users.setPhoto,users.setPresence,users.profile.get,users.profile.set,views.open,views.publish,views.push,views.update,channels.archive,channels.create,channels.history,channels.info,channels.invite,channels.join,channels.kick,channels.leave,channels.list,channels.mark,channels.rename,channels.replies,channels.setPurpose,channels.setTopic,channels.unarchive,groups.archive,groups.create,groups.createChild,groups.history,groups.info,groups.invite,groups.kick,groups.leave,groups.list,groups.mark,groups.open,groups.rename,groups.replies,groups.setPurpose,groups.setTopic,groups.unarchive,im.close,im.history,im.list,im.mark,im.open,im.replies,mpim.close,mpim.history,mpim.list,mpim.mark,mpim.open,mpim.replies".split(
13+
all_api_methods = "admin.apps.approve,admin.apps.restrict,admin.apps.approved.list,admin.apps.requests.list,admin.apps.restricted.list,admin.conversations.restrictAccess.addGroup,admin.conversations.restrictAccess.listGroups,admin.conversations.restrictAccess.removeGroup,admin.conversations.setTeams,admin.emoji.add,admin.emoji.addAlias,admin.emoji.list,admin.emoji.remove,admin.emoji.rename,admin.inviteRequests.approve,admin.inviteRequests.deny,admin.inviteRequests.list,admin.inviteRequests.approved.list,admin.inviteRequests.denied.list,admin.teams.admins.list,admin.teams.create,admin.teams.list,admin.teams.owners.list,admin.teams.settings.info,admin.teams.settings.setDefaultChannels,admin.teams.settings.setDescription,admin.teams.settings.setDiscoverability,admin.teams.settings.setIcon,admin.teams.settings.setName,admin.usergroups.addChannels,admin.usergroups.addTeams,admin.usergroups.listChannels,admin.usergroups.removeChannels,admin.users.assign,admin.users.invite,admin.users.list,admin.users.remove,admin.users.setAdmin,admin.users.setExpiration,admin.users.setOwner,admin.users.setRegular,admin.users.session.reset,api.test,apps.permissions.info,apps.permissions.request,apps.permissions.resources.list,apps.permissions.scopes.list,apps.permissions.users.list,apps.permissions.users.request,apps.uninstall,auth.revoke,auth.test,bots.info,calls.add,calls.end,calls.info,calls.update,calls.participants.add,calls.participants.remove,chat.delete,chat.deleteScheduledMessage,chat.getPermalink,chat.meMessage,chat.postEphemeral,chat.postMessage,chat.scheduleMessage,chat.unfurl,chat.update,chat.scheduledMessages.list,conversations.archive,conversations.close,conversations.create,conversations.history,conversations.info,conversations.invite,conversations.join,conversations.kick,conversations.leave,conversations.list,conversations.mark,conversations.members,conversations.open,conversations.rename,conversations.replies,conversations.setPurpose,conversations.setTopic,conversations.unarchive,dialog.open,dnd.endDnd,dnd.endSnooze,dnd.info,dnd.setSnooze,dnd.teamInfo,emoji.list,files.comments.delete,files.delete,files.info,files.list,files.revokePublicURL,files.sharedPublicURL,files.upload,files.remote.add,files.remote.info,files.remote.list,files.remote.remove,files.remote.share,files.remote.update,migration.exchange,oauth.access,oauth.token,oauth.v2.access,pins.add,pins.list,pins.remove,reactions.add,reactions.get,reactions.list,reactions.remove,reminders.add,reminders.complete,reminders.delete,reminders.info,reminders.list,rtm.connect,rtm.start,search.all,search.files,search.messages,stars.add,stars.list,stars.remove,team.accessLogs,team.billableInfo,team.info,team.integrationLogs,team.profile.get,usergroups.create,usergroups.disable,usergroups.enable,usergroups.list,usergroups.update,usergroups.users.list,usergroups.users.update,users.conversations,users.deletePhoto,users.getPresence,users.identity,users.info,users.list,users.lookupByEmail,users.setActive,users.setPhoto,users.setPresence,users.profile.get,users.profile.set,views.open,views.publish,views.push,views.update,admin.conversations.whitelist.add,admin.conversations.whitelist.listGroupsLinkedToChannel,admin.conversations.whitelist.remove,channels.archive,channels.create,channels.history,channels.info,channels.invite,channels.join,channels.kick,channels.leave,channels.list,channels.mark,channels.rename,channels.replies,channels.setPurpose,channels.setTopic,channels.unarchive,groups.archive,groups.create,groups.createChild,groups.history,groups.info,groups.invite,groups.kick,groups.leave,groups.list,groups.mark,groups.open,groups.rename,groups.replies,groups.setPurpose,groups.setTopic,groups.unarchive,im.close,im.history,im.list,im.mark,im.open,im.replies,mpim.close,mpim.history,mpim.list,mpim.mark,mpim.open,mpim.replies".split(
1414
","
1515
)
1616

@@ -26,6 +26,11 @@ def setUp(self):
2626
"oauth.v2.access",
2727
"oauth.token",
2828
"users.setActive",
29+
"admin.conversations.whitelist.add", # deprecated
30+
"admin.conversations.whitelist.listGroupsLinkedToChannel", # deprecated
31+
"admin.conversations.whitelist.remove", # deprecated
32+
"admin.usergroups.addTeams", # TODO
33+
"calls.participants.remove", # TODO
2934
]:
3035
continue
3136
self.api_methods_to_call.append(api_method)
@@ -198,6 +203,8 @@ def test_coverage(self):
198203
self.api_methods_to_call.remove(method(channel="C123", user="U123")["method"])
199204
elif method_name == "conversations_leave":
200205
self.api_methods_to_call.remove(method(channel="C123")["method"])
206+
elif method_name == "conversations_mark":
207+
self.api_methods_to_call.remove(method(channel="C123", ts="123.123")["method"])
201208
elif method_name == "conversations_members":
202209
self.api_methods_to_call.remove(method(channel="C123")["method"])
203210
elif method_name == "conversations_rename":

0 commit comments

Comments
 (0)