From 7f0bb568db51cd6984e4a98295c459c4b0fead01 Mon Sep 17 00:00:00 2001 From: Kazuhiro Sera Date: Thu, 13 Jun 2024 17:26:35 +0900 Subject: [PATCH 1/2] Add canvases APIs and users.discoverableContacts.lookup API --- integration_tests/web/test_canvases.py | 149 ++++++++++++++++++ slack_sdk/web/async_client.py | 124 +++++++++++++++ slack_sdk/web/client.py | 124 +++++++++++++++ slack_sdk/web/legacy_client.py | 124 +++++++++++++++ .../web/test_web_client_coverage.py | 50 +++++- 5 files changed, 565 insertions(+), 6 deletions(-) create mode 100644 integration_tests/web/test_canvases.py diff --git a/integration_tests/web/test_canvases.py b/integration_tests/web/test_canvases.py new file mode 100644 index 00000000..6b007c8d --- /dev/null +++ b/integration_tests/web/test_canvases.py @@ -0,0 +1,149 @@ +import logging +import os +import time +import unittest + +from integration_tests.env_variable_names import SLACK_SDK_TEST_BOT_TOKEN +from integration_tests.helpers import async_test +from slack_sdk.web import WebClient +from slack_sdk.web.async_client import AsyncWebClient + + +class TestWebClient(unittest.TestCase): + """Runs integration tests with real Slack API""" + + def setUp(self): + self.logger = logging.getLogger(__name__) + self.bot_token = os.environ[SLACK_SDK_TEST_BOT_TOKEN] + self.sync_client: WebClient = WebClient(token=self.bot_token) + self.async_client: AsyncWebClient = AsyncWebClient(token=self.bot_token) + + def tearDown(self): + pass + + def test_sync(self): + client = self.sync_client + + # Channel canvas + new_channel = client.conversations_create(name=f"test-{str(time.time()).replace('.', '-')}") + channel_id = new_channel["channel"]["id"] + channel_canvas = client.conversations_canvases_create( + channel_id=channel_id, + document_content={ + "type": "markdown", + "markdown": """# My canvas + --- + ## Hey + What's up? + """, + }, + ) + self.assertIsNone(channel_canvas.get("error")) + + # Standalone canvas + standalone_canvas = client.canvases_create( + title="My canvas", + document_content={ + "type": "markdown", + "markdown": """# My canvas + --- + ## Hey + What's up? + """, + }, + ) + self.assertIsNone(standalone_canvas.get("error")) + canvas_id = standalone_canvas.get("canvas_id") + + sections = client.canvases_sections_lookup(canvas_id=canvas_id, criteria={"contains_text": "Hey"}) + section_id = sections["sections"][0]["id"] + + edit = client.canvases_edit( + canvas_id=canvas_id, + changes=[ + { + "operation": "replace", + "section_id": section_id, + "document_content": {"type": "markdown", "markdown": "## Hey Hey"}, + } + ], + ) + self.assertIsNone(edit.get("error")) + + user_id = client.auth_test()["user_id"] + access_set = client.canvases_access_set( + canvas_id=canvas_id, + access_level="write", + user_ids=[user_id], + ) + self.assertIsNone(access_set.get("error")) + + access_delete = client.canvases_access_delete(canvas_id=canvas_id, user_ids=[user_id]) + self.assertIsNone(access_delete.get("error")) + + delete = client.canvases_delete(canvas_id=canvas_id) + self.assertIsNone(delete.get("error")) + + @async_test + async def test_async(self): + client = self.async_client + + # Channel canvas + new_channel = await client.conversations_create(name=f"test-{str(time.time()).replace('.', '-')}") + channel_id = new_channel["channel"]["id"] + channel_canvas = await client.conversations_canvases_create( + channel_id=channel_id, + document_content={ + "type": "markdown", + "markdown": """# My canvas + --- + ## Hey + What's up? + """, + }, + ) + self.assertIsNone(channel_canvas.get("error")) + + # Standalone canvas + standalone_canvas = await client.canvases_create( + title="My canvas", + document_content={ + "type": "markdown", + "markdown": """# My canvas + --- + ## Hey + What's up? + """, + }, + ) + self.assertIsNone(standalone_canvas.get("error")) + canvas_id = standalone_canvas.get("canvas_id") + + sections = await client.canvases_sections_lookup(canvas_id=canvas_id, criteria={"contains_text": "Hey"}) + section_id = sections["sections"][0]["id"] + + edit = await client.canvases_edit( + canvas_id=canvas_id, + changes=[ + { + "operation": "replace", + "section_id": section_id, + "document_content": {"type": "markdown", "markdown": "## Hey Hey"}, + } + ], + ) + self.assertIsNone(edit.get("error")) + + user_id = (await client.auth_test())["user_id"] + access_set = await client.canvases_access_set( + canvas_id=canvas_id, + access_level="write", + user_ids=[user_id], + ) + self.assertIsNone(access_set.get("error")) + + access_delete = await client.canvases_access_delete(canvas_id=canvas_id, user_ids=[user_id]) + self.assertIsNone(access_delete.get("error")) + + delete = await client.canvases_delete(canvas_id=canvas_id) + self.assertIsNone(delete.get("error")) diff --git a/slack_sdk/web/async_client.py b/slack_sdk/web/async_client.py index bd2b3a71..c4c36a32 100644 --- a/slack_sdk/web/async_client.py +++ b/slack_sdk/web/async_client.py @@ -2244,6 +2244,107 @@ async def calls_update( ) return await self.api_call("calls.update", http_verb="POST", params=kwargs) + async def canvases_create( + self, + *, + title: Optional[str] = None, + document_content: Dict[str, str], + **kwargs, + ) -> AsyncSlackResponse: + """Create Canvas for a user + https://api.slack.com/methods/canvases.create + """ + kwargs.update({"title": title, "document_content": json.dumps(document_content)}) + return await self.api_call("canvases.create", params=kwargs) + + async def canvases_edit( + self, + *, + canvas_id: str, + changes: Sequence[Dict[str, Any]], + **kwargs, + ) -> AsyncSlackResponse: + """Update an existing canvas + https://api.slack.com/methods/canvases.edit + """ + kwargs.update({"canvas_id": canvas_id, "changes": json.dumps(changes)}) + return await self.api_call("canvases.edit", params=kwargs) + + async def canvases_delete( + self, + *, + canvas_id: str, + **kwargs, + ) -> AsyncSlackResponse: + """Deletes a canvas + https://api.slack.com/methods/canvases.delete + """ + kwargs.update({"canvas_id": canvas_id}) + return await self.api_call("canvases.delete", params=kwargs) + + async def canvases_access_set( + self, + *, + canvas_id: str, + access_level: str, + channel_ids: Optional[Union[Sequence[str], str]] = None, + user_ids: Optional[Union[Sequence[str], str]] = None, + **kwargs, + ) -> AsyncSlackResponse: + """Sets the access level to a canvas for specified entities + https://api.slack.com/methods/canvases.access.set + """ + kwargs.update({"canvas_id": canvas_id, "access_level": access_level}) + if channel_ids is not None: + if isinstance(channel_ids, (list, Tuple)): + kwargs.update({"channel_ids": ",".join(channel_ids)}) + else: + kwargs.update({"channel_ids": channel_ids}) + if user_ids is not None: + if isinstance(user_ids, (list, Tuple)): + kwargs.update({"user_ids": ",".join(user_ids)}) + else: + kwargs.update({"user_ids": user_ids}) + + return await self.api_call("canvases.access.set", params=kwargs) + + async def canvases_access_delete( + self, + *, + canvas_id: str, + channel_ids: Optional[Union[Sequence[str], str]] = None, + user_ids: Optional[Union[Sequence[str], str]] = None, + **kwargs, + ) -> AsyncSlackResponse: + """Create a Channel Canvas for a channel + https://api.slack.com/methods/canvases.access.delete + """ + kwargs.update({"canvas_id": canvas_id}) + if channel_ids is not None: + if isinstance(channel_ids, (list, Tuple)): + kwargs.update({"channel_ids": ",".join(channel_ids)}) + else: + kwargs.update({"channel_ids": channel_ids}) + if user_ids is not None: + if isinstance(user_ids, (list, Tuple)): + kwargs.update({"user_ids": ",".join(user_ids)}) + else: + kwargs.update({"user_ids": user_ids}) + return await self.api_call("canvases.access.delete", params=kwargs) + + async def canvases_sections_lookup( + self, + *, + canvas_id: str, + criteria: Dict[str, Any], + **kwargs, + ) -> AsyncSlackResponse: + """Find sections matching the provided criteria + https://api.slack.com/methods/canvases.sections.lookup + """ + kwargs.update({"canvas_id": canvas_id, "criteria": json.dumps(criteria)}) + return await self.api_call("canvases.sections.lookup", params=kwargs) + # -------------------------- # Deprecated: channels.* # You can use conversations.* APIs instead. @@ -3113,6 +3214,19 @@ async def conversations_unarchive( kwargs.update({"channel": channel}) return await self.api_call("conversations.unarchive", params=kwargs) + async def conversations_canvases_create( + self, + *, + channel_id: str, + document_content: Dict[str, str], + **kwargs, + ) -> AsyncSlackResponse: + """Create a Channel Canvas for a channel + https://api.slack.com/methods/conversations.canvases.create + """ + kwargs.update({"channel_id": channel_id, "document_content": json.dumps(document_content)}) + return await self.api_call("conversations.canvases.create", params=kwargs) + async def dialog_open( self, *, @@ -4931,6 +5045,16 @@ async def users_setPresence( kwargs.update({"presence": presence}) return await self.api_call("users.setPresence", params=kwargs) + async def users_discoverableContacts_lookup( + self, + email: str, + **kwargs, + ) -> AsyncSlackResponse: + """Delete the user profile photo + https://api.slack.com/methods/users.discoverableContacts.lookup + """ + return await self.api_call("users.discoverableContacts.lookup", params=kwargs) + async def users_profile_get( self, *, diff --git a/slack_sdk/web/client.py b/slack_sdk/web/client.py index c8fddf23..7cd54ee1 100644 --- a/slack_sdk/web/client.py +++ b/slack_sdk/web/client.py @@ -2235,6 +2235,107 @@ def calls_update( ) return self.api_call("calls.update", http_verb="POST", params=kwargs) + def canvases_create( + self, + *, + title: Optional[str] = None, + document_content: Dict[str, str], + **kwargs, + ) -> SlackResponse: + """Create Canvas for a user + https://api.slack.com/methods/canvases.create + """ + kwargs.update({"title": title, "document_content": json.dumps(document_content)}) + return self.api_call("canvases.create", params=kwargs) + + def canvases_edit( + self, + *, + canvas_id: str, + changes: Sequence[Dict[str, Any]], + **kwargs, + ) -> SlackResponse: + """Update an existing canvas + https://api.slack.com/methods/canvases.edit + """ + kwargs.update({"canvas_id": canvas_id, "changes": json.dumps(changes)}) + return self.api_call("canvases.edit", params=kwargs) + + def canvases_delete( + self, + *, + canvas_id: str, + **kwargs, + ) -> SlackResponse: + """Deletes a canvas + https://api.slack.com/methods/canvases.delete + """ + kwargs.update({"canvas_id": canvas_id}) + return self.api_call("canvases.delete", params=kwargs) + + def canvases_access_set( + self, + *, + canvas_id: str, + access_level: str, + channel_ids: Optional[Union[Sequence[str], str]] = None, + user_ids: Optional[Union[Sequence[str], str]] = None, + **kwargs, + ) -> SlackResponse: + """Sets the access level to a canvas for specified entities + https://api.slack.com/methods/canvases.access.set + """ + kwargs.update({"canvas_id": canvas_id, "access_level": access_level}) + if channel_ids is not None: + if isinstance(channel_ids, (list, Tuple)): + kwargs.update({"channel_ids": ",".join(channel_ids)}) + else: + kwargs.update({"channel_ids": channel_ids}) + if user_ids is not None: + if isinstance(user_ids, (list, Tuple)): + kwargs.update({"user_ids": ",".join(user_ids)}) + else: + kwargs.update({"user_ids": user_ids}) + + return self.api_call("canvases.access.set", params=kwargs) + + def canvases_access_delete( + self, + *, + canvas_id: str, + channel_ids: Optional[Union[Sequence[str], str]] = None, + user_ids: Optional[Union[Sequence[str], str]] = None, + **kwargs, + ) -> SlackResponse: + """Create a Channel Canvas for a channel + https://api.slack.com/methods/canvases.access.delete + """ + kwargs.update({"canvas_id": canvas_id}) + if channel_ids is not None: + if isinstance(channel_ids, (list, Tuple)): + kwargs.update({"channel_ids": ",".join(channel_ids)}) + else: + kwargs.update({"channel_ids": channel_ids}) + if user_ids is not None: + if isinstance(user_ids, (list, Tuple)): + kwargs.update({"user_ids": ",".join(user_ids)}) + else: + kwargs.update({"user_ids": user_ids}) + return self.api_call("canvases.access.delete", params=kwargs) + + def canvases_sections_lookup( + self, + *, + canvas_id: str, + criteria: Dict[str, Any], + **kwargs, + ) -> SlackResponse: + """Find sections matching the provided criteria + https://api.slack.com/methods/canvases.sections.lookup + """ + kwargs.update({"canvas_id": canvas_id, "criteria": json.dumps(criteria)}) + return self.api_call("canvases.sections.lookup", params=kwargs) + # -------------------------- # Deprecated: channels.* # You can use conversations.* APIs instead. @@ -3104,6 +3205,19 @@ def conversations_unarchive( kwargs.update({"channel": channel}) return self.api_call("conversations.unarchive", params=kwargs) + def conversations_canvases_create( + self, + *, + channel_id: str, + document_content: Dict[str, str], + **kwargs, + ) -> SlackResponse: + """Create a Channel Canvas for a channel + https://api.slack.com/methods/conversations.canvases.create + """ + kwargs.update({"channel_id": channel_id, "document_content": json.dumps(document_content)}) + return self.api_call("conversations.canvases.create", params=kwargs) + def dialog_open( self, *, @@ -4922,6 +5036,16 @@ def users_setPresence( kwargs.update({"presence": presence}) return self.api_call("users.setPresence", params=kwargs) + def users_discoverableContacts_lookup( + self, + email: str, + **kwargs, + ) -> SlackResponse: + """Delete the user profile photo + https://api.slack.com/methods/users.discoverableContacts.lookup + """ + return self.api_call("users.discoverableContacts.lookup", params=kwargs) + def users_profile_get( self, *, diff --git a/slack_sdk/web/legacy_client.py b/slack_sdk/web/legacy_client.py index e77f57e1..c5917ff3 100644 --- a/slack_sdk/web/legacy_client.py +++ b/slack_sdk/web/legacy_client.py @@ -2246,6 +2246,107 @@ def calls_update( ) return self.api_call("calls.update", http_verb="POST", params=kwargs) + def canvases_create( + self, + *, + title: Optional[str] = None, + document_content: Dict[str, str], + **kwargs, + ) -> Union[Future, SlackResponse]: + """Create Canvas for a user + https://api.slack.com/methods/canvases.create + """ + kwargs.update({"title": title, "document_content": json.dumps(document_content)}) + return self.api_call("canvases.create", params=kwargs) + + def canvases_edit( + self, + *, + canvas_id: str, + changes: Sequence[Dict[str, Any]], + **kwargs, + ) -> Union[Future, SlackResponse]: + """Update an existing canvas + https://api.slack.com/methods/canvases.edit + """ + kwargs.update({"canvas_id": canvas_id, "changes": json.dumps(changes)}) + return self.api_call("canvases.edit", params=kwargs) + + def canvases_delete( + self, + *, + canvas_id: str, + **kwargs, + ) -> Union[Future, SlackResponse]: + """Deletes a canvas + https://api.slack.com/methods/canvases.delete + """ + kwargs.update({"canvas_id": canvas_id}) + return self.api_call("canvases.delete", params=kwargs) + + def canvases_access_set( + self, + *, + canvas_id: str, + access_level: str, + channel_ids: Optional[Union[Sequence[str], str]] = None, + user_ids: Optional[Union[Sequence[str], str]] = None, + **kwargs, + ) -> Union[Future, SlackResponse]: + """Sets the access level to a canvas for specified entities + https://api.slack.com/methods/canvases.access.set + """ + kwargs.update({"canvas_id": canvas_id, "access_level": access_level}) + if channel_ids is not None: + if isinstance(channel_ids, (list, Tuple)): + kwargs.update({"channel_ids": ",".join(channel_ids)}) + else: + kwargs.update({"channel_ids": channel_ids}) + if user_ids is not None: + if isinstance(user_ids, (list, Tuple)): + kwargs.update({"user_ids": ",".join(user_ids)}) + else: + kwargs.update({"user_ids": user_ids}) + + return self.api_call("canvases.access.set", params=kwargs) + + def canvases_access_delete( + self, + *, + canvas_id: str, + channel_ids: Optional[Union[Sequence[str], str]] = None, + user_ids: Optional[Union[Sequence[str], str]] = None, + **kwargs, + ) -> Union[Future, SlackResponse]: + """Create a Channel Canvas for a channel + https://api.slack.com/methods/canvases.access.delete + """ + kwargs.update({"canvas_id": canvas_id}) + if channel_ids is not None: + if isinstance(channel_ids, (list, Tuple)): + kwargs.update({"channel_ids": ",".join(channel_ids)}) + else: + kwargs.update({"channel_ids": channel_ids}) + if user_ids is not None: + if isinstance(user_ids, (list, Tuple)): + kwargs.update({"user_ids": ",".join(user_ids)}) + else: + kwargs.update({"user_ids": user_ids}) + return self.api_call("canvases.access.delete", params=kwargs) + + def canvases_sections_lookup( + self, + *, + canvas_id: str, + criteria: Dict[str, Any], + **kwargs, + ) -> Union[Future, SlackResponse]: + """Find sections matching the provided criteria + https://api.slack.com/methods/canvases.sections.lookup + """ + kwargs.update({"canvas_id": canvas_id, "criteria": json.dumps(criteria)}) + return self.api_call("canvases.sections.lookup", params=kwargs) + # -------------------------- # Deprecated: channels.* # You can use conversations.* APIs instead. @@ -3115,6 +3216,19 @@ def conversations_unarchive( kwargs.update({"channel": channel}) return self.api_call("conversations.unarchive", params=kwargs) + def conversations_canvases_create( + self, + *, + channel_id: str, + document_content: Dict[str, str], + **kwargs, + ) -> Union[Future, SlackResponse]: + """Create a Channel Canvas for a channel + https://api.slack.com/methods/conversations.canvases.create + """ + kwargs.update({"channel_id": channel_id, "document_content": json.dumps(document_content)}) + return self.api_call("conversations.canvases.create", params=kwargs) + def dialog_open( self, *, @@ -4933,6 +5047,16 @@ def users_setPresence( kwargs.update({"presence": presence}) return self.api_call("users.setPresence", params=kwargs) + def users_discoverableContacts_lookup( + self, + email: str, + **kwargs, + ) -> Union[Future, SlackResponse]: + """Delete the user profile photo + https://api.slack.com/methods/users.discoverableContacts.lookup + """ + return self.api_call("users.discoverableContacts.lookup", params=kwargs) + def users_profile_get( self, *, diff --git a/tests/slack_sdk_async/web/test_web_client_coverage.py b/tests/slack_sdk_async/web/test_web_client_coverage.py index 08dc7365..1da0c481 100644 --- a/tests/slack_sdk_async/web/test_web_client_coverage.py +++ b/tests/slack_sdk_async/web/test_web_client_coverage.py @@ -4,20 +4,20 @@ import slack_sdk.errors as e from slack_sdk.models.blocks import DividerBlock from slack_sdk.models.views import View +from slack_sdk.web import WebClient from slack_sdk.web.async_client import AsyncWebClient from slack_sdk.web.legacy_client import LegacyWebClient -from slack_sdk.web import WebClient -from tests.slack_sdk_async.helpers import async_test from tests.slack_sdk.web.mock_web_api_server import ( setup_mock_web_api_server, cleanup_mock_web_api_server, ) +from tests.slack_sdk_async.helpers import async_test class TestWebClientCoverage(unittest.TestCase): - # 260 endpoints as of September 7, 2023 + # 284 endpoints as of June 12, 2024 # Can be fetched by running `var methodNames = [].slice.call(document.getElementsByClassName('apiReferenceFilterableList__listItemLink')).map(e => e.href.replace("https://api.slack.com/methods/", ""));console.log(methodNames.toString());console.log(methodNames.length);` on https://api.slack.com/methods - all_api_methods = "admin.analytics.getFile,admin.apps.activities.list,admin.apps.approve,admin.apps.clearResolution,admin.apps.restrict,admin.apps.uninstall,admin.apps.approved.list,admin.apps.config.lookup,admin.apps.config.set,admin.apps.requests.cancel,admin.apps.requests.list,admin.apps.restricted.list,admin.audit.anomaly.allow.getItem,admin.audit.anomaly.allow.updateItem,admin.auth.policy.assignEntities,admin.auth.policy.getEntities,admin.auth.policy.removeEntities,admin.barriers.create,admin.barriers.delete,admin.barriers.list,admin.barriers.update,admin.conversations.archive,admin.conversations.bulkArchive,admin.conversations.bulkDelete,admin.conversations.bulkMove,admin.conversations.convertToPrivate,admin.conversations.convertToPublic,admin.conversations.create,admin.conversations.delete,admin.conversations.disconnectShared,admin.conversations.getConversationPrefs,admin.conversations.getCustomRetention,admin.conversations.getTeams,admin.conversations.invite,admin.conversations.lookup,admin.conversations.removeCustomRetention,admin.conversations.rename,admin.conversations.search,admin.conversations.setConversationPrefs,admin.conversations.setCustomRetention,admin.conversations.setTeams,admin.conversations.unarchive,admin.conversations.ekm.listOriginalConnectedChannelInfo,admin.conversations.restrictAccess.addGroup,admin.conversations.restrictAccess.listGroups,admin.conversations.restrictAccess.removeGroup,admin.emoji.add,admin.emoji.addAlias,admin.emoji.list,admin.emoji.remove,admin.emoji.rename,admin.functions.list,admin.functions.permissions.lookup,admin.functions.permissions.set,admin.inviteRequests.approve,admin.inviteRequests.deny,admin.inviteRequests.list,admin.inviteRequests.approved.list,admin.inviteRequests.denied.list,admin.roles.addAssignments,admin.roles.listAssignments,admin.roles.removeAssignments,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.clearSettings,admin.users.session.getSettings,admin.users.session.invalidate,admin.users.session.list,admin.users.session.reset,admin.users.session.resetBulk,admin.users.session.setSettings,admin.users.unsupportedVersions.export,admin.workflows.collaborators.add,admin.workflows.collaborators.remove,admin.workflows.permissions.lookup,admin.workflows.search,admin.workflows.unpublish,api.test,apps.activities.list,apps.auth.external.delete,apps.auth.external.get,apps.connections.open,apps.datastore.delete,apps.datastore.get,apps.datastore.put,apps.datastore.query,apps.datastore.update,apps.event.authorizations.list,apps.manifest.create,apps.manifest.delete,apps.manifest.export,apps.manifest.update,apps.manifest.validate,apps.uninstall,auth.revoke,auth.test,auth.teams.list,bookmarks.add,bookmarks.edit,bookmarks.list,bookmarks.remove,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.acceptSharedInvite,conversations.approveSharedInvite,conversations.archive,conversations.close,conversations.create,conversations.declineSharedInvite,conversations.history,conversations.info,conversations.invite,conversations.inviteShared,conversations.join,conversations.kick,conversations.leave,conversations.list,conversations.listConnectInvites,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.completeUploadExternal,files.delete,files.getUploadURLExternal,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,functions.workflows.steps.list,functions.workflows.steps.responses.export,migration.exchange,oauth.access,oauth.v2.access,oauth.v2.exchange,openid.connect.token,openid.connect.userInfo,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.billing.info,team.preferences.list,team.profile.get,tooling.tokens.rotate,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,workflows.stepCompleted,workflows.stepFailed,workflows.updateStep,channels.create,channels.info,channels.invite,channels.mark,groups.create,groups.info,groups.invite,groups.mark,groups.open,im.list,im.mark,im.open,mpim.list,mpim.mark,mpim.open".split( + all_api_methods = "admin.analytics.getFile,admin.apps.activities.list,admin.apps.approve,admin.apps.clearResolution,admin.apps.restrict,admin.apps.uninstall,admin.apps.approved.list,admin.apps.config.lookup,admin.apps.config.set,admin.apps.requests.cancel,admin.apps.requests.list,admin.apps.restricted.list,admin.audit.anomaly.allow.getItem,admin.audit.anomaly.allow.updateItem,admin.auth.policy.assignEntities,admin.auth.policy.getEntities,admin.auth.policy.removeEntities,admin.barriers.create,admin.barriers.delete,admin.barriers.list,admin.barriers.update,admin.conversations.archive,admin.conversations.bulkArchive,admin.conversations.bulkDelete,admin.conversations.bulkMove,admin.conversations.convertToPrivate,admin.conversations.convertToPublic,admin.conversations.create,admin.conversations.delete,admin.conversations.disconnectShared,admin.conversations.getConversationPrefs,admin.conversations.getCustomRetention,admin.conversations.getTeams,admin.conversations.invite,admin.conversations.lookup,admin.conversations.removeCustomRetention,admin.conversations.rename,admin.conversations.search,admin.conversations.setConversationPrefs,admin.conversations.setCustomRetention,admin.conversations.setTeams,admin.conversations.unarchive,admin.conversations.ekm.listOriginalConnectedChannelInfo,admin.conversations.restrictAccess.addGroup,admin.conversations.restrictAccess.listGroups,admin.conversations.restrictAccess.removeGroup,admin.emoji.add,admin.emoji.addAlias,admin.emoji.list,admin.emoji.remove,admin.emoji.rename,admin.functions.list,admin.functions.permissions.lookup,admin.functions.permissions.set,admin.inviteRequests.approve,admin.inviteRequests.deny,admin.inviteRequests.list,admin.inviteRequests.approved.list,admin.inviteRequests.denied.list,admin.roles.addAssignments,admin.roles.listAssignments,admin.roles.removeAssignments,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.clearSettings,admin.users.session.getSettings,admin.users.session.invalidate,admin.users.session.list,admin.users.session.reset,admin.users.session.resetBulk,admin.users.session.setSettings,admin.users.unsupportedVersions.export,admin.workflows.collaborators.add,admin.workflows.collaborators.remove,admin.workflows.permissions.lookup,admin.workflows.search,admin.workflows.unpublish,admin.workflows.triggers.types.permissions.lookup,admin.workflows.triggers.types.permissions.set,api.test,apps.activities.list,apps.auth.external.delete,apps.auth.external.get,apps.connections.open,apps.datastore.bulkDelete,apps.datastore.bulkGet,apps.datastore.bulkPut,apps.datastore.count,apps.datastore.delete,apps.datastore.get,apps.datastore.put,apps.datastore.query,apps.datastore.update,apps.event.authorizations.list,apps.manifest.create,apps.manifest.delete,apps.manifest.export,apps.manifest.update,apps.manifest.validate,apps.uninstall,auth.revoke,auth.test,auth.teams.list,bookmarks.add,bookmarks.edit,bookmarks.list,bookmarks.remove,bots.info,calls.add,calls.end,calls.info,calls.update,calls.participants.add,calls.participants.remove,canvases.access.delete,canvases.access.set,canvases.create,canvases.delete,canvases.edit,canvases.sections.lookup,chat.delete,chat.deleteScheduledMessage,chat.getPermalink,chat.meMessage,chat.postEphemeral,chat.postMessage,chat.scheduleMessage,chat.unfurl,chat.update,chat.scheduledMessages.list,conversations.acceptSharedInvite,conversations.approveSharedInvite,conversations.archive,conversations.close,conversations.create,conversations.declineSharedInvite,conversations.history,conversations.info,conversations.invite,conversations.inviteShared,conversations.join,conversations.kick,conversations.leave,conversations.list,conversations.listConnectInvites,conversations.mark,conversations.members,conversations.open,conversations.rename,conversations.replies,conversations.setPurpose,conversations.setTopic,conversations.unarchive,conversations.canvases.create,dialog.open,dnd.endDnd,dnd.endSnooze,dnd.info,dnd.setSnooze,dnd.teamInfo,emoji.list,files.comments.delete,files.completeUploadExternal,files.delete,files.getUploadURLExternal,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,functions.completeError,functions.completeSuccess,functions.distributions.permissions.add,functions.distributions.permissions.list,functions.distributions.permissions.remove,functions.distributions.permissions.set,functions.workflows.steps.list,functions.workflows.steps.responses.export,migration.exchange,oauth.access,oauth.v2.access,oauth.v2.exchange,openid.connect.token,openid.connect.userInfo,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.billing.info,team.preferences.list,team.profile.get,tooling.tokens.rotate,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.discoverableContacts.lookup,users.profile.get,users.profile.set,views.open,views.publish,views.push,views.update,workflows.stepCompleted,workflows.stepFailed,workflows.updateStep,workflows.triggers.permissions.add,workflows.triggers.permissions.list,workflows.triggers.permissions.remove,workflows.triggers.permissions.set,channels.create,channels.info,channels.invite,channels.mark,groups.create,groups.info,groups.invite,groups.mark,groups.open,im.list,im.mark,im.open,mpim.list,mpim.mark,mpim.open".split( "," ) @@ -50,8 +50,22 @@ def setUp(self): "apps.datastore.put", "apps.datastore.query", "apps.datastore.update", + "apps.datastore.bulkDelete", + "apps.datastore.bulkGet", + "apps.datastore.bulkPut", + "apps.datastore.count", "functions.workflows.steps.list", "functions.workflows.steps.responses.export", + "functions.distributions.permissions.add", + "functions.distributions.permissions.list", + "functions.distributions.permissions.remove", + "functions.distributions.permissions.set", + "workflows.triggers.permissions.add", + "workflows.triggers.permissions.list", + "workflows.triggers.permissions.remove", + "workflows.triggers.permissions.set", + "admin.workflows.triggers.types.permissions.lookup", + "admin.workflows.triggers.types.permissions.set", # TODO: admin.audit.anomaly.allow.* / The endpoints requires a "session" token "admin.audit.anomaly.allow.getItem", "admin.audit.anomaly.allow.updateItem", @@ -462,6 +476,27 @@ async def run_method(self, method_name, method, async_method): elif method_name == "calls_update": self.api_methods_to_call.remove(method(id="R111")["method"]) await async_method(id="R111") + elif method_name == "canvases_create": + self.api_methods_to_call.remove(method(document_content={})["method"]) + await async_method(document_content={}) + elif method_name == "conversations_canvases_create": + self.api_methods_to_call.remove(method(channel_id="C123", document_content={})["method"]) + await async_method(channel_id="C123", document_content={}) + elif method_name == "canvases_access_set": + self.api_methods_to_call.remove(method(canvas_id="F111", access_level="write")["method"]) + await async_method(canvas_id="F111", access_level="write") + elif method_name == "canvases_access_delete": + self.api_methods_to_call.remove(method(canvas_id="F111")["method"]) + await async_method(canvas_id="F111") + elif method_name == "canvases_delete": + self.api_methods_to_call.remove(method(canvas_id="F111")["method"]) + await async_method(canvas_id="F111") + elif method_name == "canvases_edit": + self.api_methods_to_call.remove(method(canvas_id="F111", changes=[])["method"]) + await async_method(canvas_id="F111", changes=[]) + elif method_name == "canvases_sections_lookup": + self.api_methods_to_call.remove(method(canvas_id="F123", criteria={})["method"]) + await async_method(canvas_id="F123", criteria={}) elif method_name == "chat_delete": self.api_methods_to_call.remove(method(channel="C123", ts="123.123")["method"]) await async_method(channel="C123", ts="123.123") @@ -641,10 +676,10 @@ async def run_method(self, method_name, method, async_method): self.api_methods_to_call.remove(method(files=[{"id": "F111"}])["method"]) await async_method(files=[{"id": "F111"}]) elif method_name == "functions_completeSuccess": - self.api_methods_to_call.remove(method(function_execution_id="Fn111", outputs={"num": 123})) + self.api_methods_to_call.remove(method(function_execution_id="Fn111", outputs={"num": 123})["method"]) await async_method(function_execution_id="Fn111", outputs={"num": 123}) elif method_name == "functions_completeError": - self.api_methods_to_call.remove(method(function_execution_id="Fn111", error="something wrong")) + self.api_methods_to_call.remove(method(function_execution_id="Fn111", error="something wrong")["method"]) await async_method(function_execution_id="Fn111", error="something wrong") elif method_name == "migration_exchange": self.api_methods_to_call.remove(method(users="U123,U234")["method"]) @@ -956,6 +991,9 @@ async def run_method(self, method_name, method, async_method): elif method_name == "admin_conversations_lookup": self.api_methods_to_call.remove(method(team_ids=["T111", "T222"], last_message_activity_before=10)["method"]) await async_method(team_ids=["T111", "T222"], last_message_activity_before=10) + elif method_name == "users_discoverableContacts_lookup": + self.api_methods_to_call.remove(method(email="foo@example.com")["method"]) + await async_method(email="foo@example.com") else: self.api_methods_to_call.remove(method(*{})["method"]) await async_method(*{}) From 3f059ef83ccbb22c6a06fc96bbef054c32a526eb Mon Sep 17 00:00:00 2001 From: Kazuhiro Sera Date: Thu, 13 Jun 2024 22:36:18 +0900 Subject: [PATCH 2/2] Update slack_sdk/web/async_client.py Co-authored-by: Fil Maj --- slack_sdk/web/async_client.py | 3 ++- slack_sdk/web/client.py | 3 ++- slack_sdk/web/legacy_client.py | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/slack_sdk/web/async_client.py b/slack_sdk/web/async_client.py index c4c36a32..789f1c5d 100644 --- a/slack_sdk/web/async_client.py +++ b/slack_sdk/web/async_client.py @@ -5050,9 +5050,10 @@ async def users_discoverableContacts_lookup( email: str, **kwargs, ) -> AsyncSlackResponse: - """Delete the user profile photo + """Lookup an email address to see if someone is on Slack https://api.slack.com/methods/users.discoverableContacts.lookup """ + kwargs.update({"email": email}) return await self.api_call("users.discoverableContacts.lookup", params=kwargs) async def users_profile_get( diff --git a/slack_sdk/web/client.py b/slack_sdk/web/client.py index 7cd54ee1..1813cfc0 100644 --- a/slack_sdk/web/client.py +++ b/slack_sdk/web/client.py @@ -5041,9 +5041,10 @@ def users_discoverableContacts_lookup( email: str, **kwargs, ) -> SlackResponse: - """Delete the user profile photo + """Lookup an email address to see if someone is on Slack https://api.slack.com/methods/users.discoverableContacts.lookup """ + kwargs.update({"email": email}) return self.api_call("users.discoverableContacts.lookup", params=kwargs) def users_profile_get( diff --git a/slack_sdk/web/legacy_client.py b/slack_sdk/web/legacy_client.py index c5917ff3..ea33b981 100644 --- a/slack_sdk/web/legacy_client.py +++ b/slack_sdk/web/legacy_client.py @@ -5052,9 +5052,10 @@ def users_discoverableContacts_lookup( email: str, **kwargs, ) -> Union[Future, SlackResponse]: - """Delete the user profile photo + """Lookup an email address to see if someone is on Slack https://api.slack.com/methods/users.discoverableContacts.lookup """ + kwargs.update({"email": email}) return self.api_call("users.discoverableContacts.lookup", params=kwargs) def users_profile_get(