class SlackClient(object): def __init__(self, token=None): self.client = WebClient(token=token or Config.SLACK_OAUTH_ACCESS_TOKEN) def post_message_to_channel(self, channel: str, message: str): try: response = self.client.chat_postMessage(channel=channel, text=message) return response.get('message') except SlackApiError as e: # You will get a SlackApiError if "ok" is False print(f"Got an error: {e.response['error']}") def post_blocks_message_to_channel(self, channel: str, blocks: list): try: response = self.client.chat_postMessage(channel=channel, blocks=blocks) return response.get('message') except SlackApiError as e: print(f"Got an error: {e.response['error']}") def create_direct_message(self, users: list): response = self.client.conversations_open(users=users) if response.data.get('ok'): return response.get('channel') def get_user_by_email(self, email: str) -> SlackResponse: user = self.client.api_call(api_method='users.lookupByEmail', params={"email": email}) if user.data.get('ok'): return user.data.get('user')
class SlackHelper: def __init__(self): self.slack_token = get_env('SLACK_TOKEN') # formerly known as slackclient self.slack_client = WebClient(token=self.slack_token) self.slack_channel = get_env('SLACK_CHANNEL') def post_message(self, msg, recipient): try: return self.slack_client.chat_postMessage( channel=recipient, text=msg, ) except SlackApiError as e: print(f"Error posting message: {e}") # return self.slack_client.api_call( # "chat.postMessage", # channel=recipient, # text=msg, # as_user=True # ) def post_message_to_channel(self, msg): try: return self.slack_client.chat_postMessage( channel=self.slack_channel, text=msg, ) except SlackApiError as e: print(f"Error posting message: {e}") # return self.slack_client.api_call( # "chat.postMessage", # channel=self.slack_channel, # text=msg, # username='******', # parse='full', # as_user=False # ) # additional methods to interact with slack def file_upload( self, file_content, file_name, file_type, title=None, ): return self.slack_client.api_call( "files.upload", channels=self.slack_channel, content=file_content, filename=file_name, filetype=file_type, initial_comment='{} Log File'.format(file_name), title=title) def user_info(self, uid): return self.slack_client.users_info(user=uid)
class Provider(AbstractProvider): def __init__(self, slack_token): self.sc = WebClient(slack_token) def api_call(self, *args, **kwargs): try: return self.sc.api_call(*args, **kwargs) except Exception: sleep(1) return self.sc.api_call(*args, **kwargs) def test_api_call(self, *args, **kwargs): if args[0] == "users.list": return { "members": [{ "id": "1", "profile": { "first_name": "Firstname", "last_name": "Lastename" } }, { "id": "2", "profile": { "first_name": "Secondname", "last_name": "Lastename" } }] } if args[0] == "conversations.list": return {"channels": [{"id": "1"}]} if args[0] == "conversations.history": return { "messages": [{ "user": "******", "text": "First Message", "ts": "1234567" }, { "user": "******", "text": "Second Message", "ts": "1234568" }, { "user": "******", "text": "Third Message", "ts": "1234569" }] }
def execute(body: dict, client: WebClient): step = body["event"]["workflow_step"] completion: SlackResponse = client.api_call( api_method="workflows.stepCompleted", json={ "workflow_step_execute_id": step["workflow_step_execute_id"], "outputs": { "taskName": step["inputs"]["taskName"]["value"], "taskDescription": step["inputs"]["taskDescription"]["value"], "taskAuthorEmail": step["inputs"]["taskAuthorEmail"]["value"], }, }, ) user: SlackResponse = client.users_lookupByEmail( email=step["inputs"]["taskAuthorEmail"]["value"]) user_id = user["user"]["id"] new_task = { "task_name": step["inputs"]["taskName"]["value"], "task_description": step["inputs"]["taskDescription"]["value"], } tasks = pseudo_database.get(user_id, []) tasks.append(new_task) pseudo_database[user_id] = tasks blocks = [] for task in tasks: blocks.append({ "type": "section", "text": { "type": "plain_text", "text": task["task_name"] }, }) blocks.append({"type": "divider"}) home_tab_update: SlackResponse = client.views_publish( user_id=user_id, view={ "type": "home", "title": { "type": "plain_text", "text": "Your tasks!" }, "blocks": blocks, }, )
def save(ack: Ack, client: WebClient, body: dict): state_values = body["view"]["state"]["values"] response: SlackResponse = client.api_call( api_method="workflows.updateStep", json={ "workflow_step_edit_id": body["workflow_step"]["workflow_step_edit_id"], "inputs": { "taskName": { "value": state_values["task_name_input"]["task_name"]["value"], }, "taskDescription": { "value": state_values["task_description_input"]["task_description"] ["value"], }, "taskAuthorEmail": { "value": state_values["task_author_input"]["task_author"]["value"], }, }, "outputs": [ { "name": "taskName", "type": "text", "label": "Task Name", }, { "name": "taskDescription", "type": "text", "label": "Task Description", }, { "name": "taskAuthorEmail", "type": "text", "label": "Task Author Email", }, ], }, ) ack()
def sendMessageFromQueue(self): try: ### PREPARE CLIENT ### client = WebClient(self.slackToken) ### RETRIEVE CHANNEL ID ### channels = client.api_call('conversations.list')['channels'] for channel in channels: if channel['name'] == self.channelName: channelID = channel.get('id') break while not self.threadExitSignal.is_set() or not self.count: while self.messageQueue: ### POP MESSAGE FROM QUEUE ### queueMessage = self.messageQueue.pop(0) ### SEND MESSAGE ### client.chat_postMessage(channel=channelID, text=queueMessage) time.sleep(1) self.count += 1 except Exception as error: print("ERROR: Class Slack , sendMessageFromQueue ... {error}".format(error=error))
class SlackHook(BaseHook): """ Creates a Slack connection to be used for calls. Takes both Slack API token directly and connection that has Slack API token. If both are supplied, Slack API token will be used. Also exposes the rest of slack.WebClient args. Examples: .. code-block:: python # Create hook slack_hook = SlackHook(token="xxx") # or slack_hook = SlackHook(slack_conn_id="slack") # Call generic API with parameters (errors are handled by hook) # For more details check https://api.slack.com/methods/chat.postMessage slack_hook.call("chat.postMessage", json={"channel": "#random", "text": "Hello world!"}) # Call method from Slack SDK (you have to handle errors yourself) # For more details check https://slack.dev/python-slack-sdk/web/index.html#messaging slack_hook.client.chat_postMessage(channel="#random", text="Hello world!") :param token: Slack API token :param slack_conn_id: :ref:`Slack connection id <howto/connection:slack>` that has Slack API token in the password field. :param use_session: A boolean specifying if the client should take advantage of connection pooling. Default is True. :param base_url: A string representing the Slack API base URL. Default is ``https://www.slack.com/api/`` :param timeout: The maximum number of seconds the client will wait to connect and receive a response from Slack. Default is 30 seconds. """ def __init__( self, token: Optional[str] = None, slack_conn_id: Optional[str] = None, **client_args: Any, ) -> None: super().__init__() self.token = self.__get_token(token, slack_conn_id) self.client = WebClient(self.token, **client_args) def __get_token(self, token: Any, slack_conn_id: Any) -> str: if token is not None: return token if slack_conn_id is not None: conn = self.get_connection(slack_conn_id) if not getattr(conn, 'password', None): raise AirflowException( 'Missing token(password) in Slack connection') return conn.password raise AirflowException( 'Cannot get token: No valid Slack token nor slack_conn_id supplied.' ) def call(self, api_method: str, **kwargs) -> None: """ Calls Slack WebClient `WebClient.api_call` with given arguments. :param api_method: The target Slack API method. e.g. 'chat.postMessage'. Required. :param http_verb: HTTP Verb. Optional (defaults to 'POST') :param files: Files to multipart upload. e.g. {imageORfile: file_objectORfile_path} :param data: The body to attach to the request. If a dictionary is provided, form-encoding will take place. Optional. :param params: The URL parameters to append to the URL. Optional. :param json: JSON for the body to attach to the request. Optional. """ self.client.api_call(api_method, **kwargs)
class TestWebClient(unittest.TestCase): def setUp(self): setup_mock_web_api_server(self) self.client = WebClient( token="xoxb-api_test", base_url="http://localhost:8888", ) def tearDown(self): cleanup_mock_web_api_server(self) pattern_for_language = re.compile("python/(\\S+)", re.IGNORECASE) pattern_for_package_identifier = re.compile("slackclient/(\\S+)") def test_subsequent_requests_with_a_session_succeeds(self): resp = self.client.api_test() assert resp["ok"] resp = self.client.api_test() assert resp["ok"] def test_api_calls_include_user_agent(self): self.client.token = "xoxb-api_test" resp = self.client.api_test() self.assertEqual(200, resp.status_code) def test_builtin_api_methods_send_json(self): self.client.token = "xoxb-api_test" resp = self.client.api_test(msg="bye") self.assertEqual(200, resp.status_code) self.assertEqual("bye", resp["args"]["msg"]) def test_requests_can_be_paginated(self): self.client.token = "xoxb-users_list_pagination" users = [] for page in self.client.users_list(limit=2): users = users + page["members"] self.assertTrue(len(users) == 4) def test_response_can_be_paginated_multiple_times(self): self.client.token = "xoxb-conversations_list_pagination" # This test suite verifies the changes in #521 work as expected response = self.client.conversations_list(limit=1) ids = [] for page in response: ids.append(page["channels"][0]["id"]) self.assertEqual(ids, ["C1", "C2", "C3"]) # The second iteration starting with page 2 # (page1 is already cached in `response`) self.client.token = "xoxb-conversations_list_pagination2" ids = [] for page in response: ids.append(page["channels"][0]["id"]) self.assertEqual(ids, ["C1", "C2", "C3"]) def test_request_pagination_stops_when_next_cursor_is_missing(self): self.client.token = "xoxb-users_list_pagination_1" users = [] for page in self.client.users_list(limit=2): users = users + page["members"] self.assertTrue(len(users) == 2) def test_json_can_only_be_sent_with_post_requests(self): with self.assertRaises(err.SlackRequestError): self.client.api_call("fake.method", http_verb="GET", json={}) def test_slack_api_error_is_raised_on_unsuccessful_responses(self): self.client.token = "xoxb-api_test_false" with self.assertRaises(err.SlackApiError): self.client.api_test() self.client.token = "xoxb-500" with self.assertRaises(err.SlackApiError): self.client.api_test() def test_slack_api_rate_limiting_exception_returns_retry_after(self): self.client.token = "xoxb-rate_limited" try: self.client.api_test() except err.SlackApiError as slack_api_error: self.assertFalse(slack_api_error.response["ok"]) self.assertEqual(429, slack_api_error.response.status_code) self.assertEqual(30, int(slack_api_error.response.headers["Retry-After"])) def test_the_api_call_files_argument_creates_the_expected_data(self): self.client.token = "xoxb-users_setPhoto" resp = self.client.users_setPhoto( image="tests/slack_sdk_fixture/slack_logo.png" ) self.assertEqual(200, resp.status_code) def test_issue_560_bool_in_params_sync(self): self.client.token = "xoxb-conversations_list" self.client.conversations_list(exclude_archived=1) # ok self.client.conversations_list(exclude_archived="true") # ok self.client.conversations_list(exclude_archived=True) # ok def test_issue_690_oauth_v2_access(self): self.client.token = "" resp = self.client.oauth_v2_access( client_id="111.222", client_secret="secret", code="codeeeeeeeeee" ) self.assertIsNone(resp["error"]) with self.assertRaises(err.SlackApiError): self.client.oauth_v2_access( client_id="999.999", client_secret="secret", code="codeeeeeeeeee" ) def test_issue_690_oauth_access(self): self.client.token = "" resp = self.client.oauth_access( client_id="111.222", client_secret="secret", code="codeeeeeeeeee" ) self.assertIsNone(resp["error"]) with self.assertRaises(err.SlackApiError): self.client.oauth_access( client_id="999.999", client_secret="secret", code="codeeeeeeeeee" ) def test_issue_705_no_param_request_pagination(self): self.client.token = "xoxb-users_list_pagination" users = [] for page in self.client.users_list(): users = users + page["members"] self.assertTrue(len(users) == 4) def test_token_param(self): client = WebClient(base_url="http://localhost:8888") with self.assertRaises(err.SlackApiError): client.users_list() resp = client.users_list(token="xoxb-users_list_pagination") self.assertIsNone(resp["error"]) with self.assertRaises(err.SlackApiError): client.users_list() def test_timeout_issue_712(self): client = WebClient(base_url="http://localhost:8888", timeout=1) with self.assertRaises(socket.timeout): client.users_list(token="xoxb-timeout") def test_html_response_body_issue_718(self): client = WebClient(base_url="http://localhost:8888") try: client.users_list(token="xoxb-html_response") self.fail("SlackApiError expected here") except err.SlackApiError as e: self.assertTrue( str(e).startswith( "Received a response in a non-JSON format: <!DOCTYPE HTML PUBLIC" ), e, ) def test_user_agent_customization_issue_769(self): client = WebClient( base_url="http://localhost:8888", token="xoxb-user-agent this_is test", user_agent_prefix="this_is", user_agent_suffix="test", ) resp = client.api_test() self.assertTrue(resp["ok"]) def test_default_team_id(self): client = WebClient(base_url="http://localhost:8888", team_id="T_DEFAULT") resp = client.users_list(token="xoxb-users_list_pagination") self.assertIsNone(resp["error"])
from pathlib import Path from dotenv import load_dotenv from flask import Flask, request, make_response from slackeventsapi import SlackEventAdapter from WebDex import poke_dex_info env_path = Path('.') / '.env' load_dotenv(dotenv_path=env_path) app = Flask(__name__) slack_events_adapter = SlackEventAdapter(os.environ['SLACK_SIGNIG'], '/slack/events', app) client = WebClient(token=os.environ['SLACK_TOKEN']) BOT_ID = client.api_call("auth.test")['user_id'] @slack_events_adapter.on('message') def message(payload): # print(payload) event = payload.get('event', {}) channel_id = event.get('channel') user_id = event.get('user') text = event.get('text') # print(channel_id) if text is not None: text_equals = text[0:4] == "!도감 " else: return
def slack_api_call(token, method, params): client = WebClient(token=token) response = client.api_call(api_method=method, params=params) print(response) return response
import os from slack_sdk import WebClient client = WebClient(token=os.environ['SLACK_BOT_TOKEN']) response = client.api_call(api_method='chat.postMessage', json={ 'channel': '#updates', 'text': "Hello world!" }) assert response["message"]["text"] == "Hello world!"
for k, v in post_format.items(): globals()[k] = v with open(cyclenumber_file_path) as f: cyclenumber = int(f.readline()) # read the previous record last_writer, lastweek_id = get_last_writer(week_id, lookback_weeks, history_file_path_format) if args.slacktoken: token = args.slacktoken else: with open(slacktoken_file_path, 'r') as f: token = f.readline().rstrip() web_client = WebClient(token=token) channel_id = get_channel_id(web_client, channel_name) my_id = web_client.api_call('auth.test')['user_id'] writers_dict = dict() if args.reminder: while week_id >= thisweek_id: hf = history_file_path_format.format(week_id) if os.path.exists(hf): last_writer, _ = get_last_writer(week_id, lookback_weeks, history_file_path_format) with open(hf, 'r') as f: cur_hash = hashf(last_writer) delta_cycle = 0 lines = f.readlines() for line in lines: date, person = line.rstrip().split()[:2] prev_hash = cur_hash cur_hash = hashf(person)
class SlackApi: """Wrapper around Slack API calls""" def __init__(self, workspace_name: str, token: Mapping[str, str], api_config: Optional[SlackApiConfig] = None, settings: Optional[Mapping[str, Any]] = None, init_usergroups=True, channel: Optional[str] = None, **chat_kwargs) -> None: """ :param workspace_name: Slack workspace name (ex. coreos) :param token: data to pass to SecretReader.read() to get the token :param api_config: Slack API configuration :param settings: settings to pass to SecretReader :param init_usergroups: whether or not to get a list of all Slack usergroups when instantiated :param channel: the Slack channel to post messages to, only used when posting messages to a channel :param chat_kwargs: any other kwargs that can be used to post Slack channel messages """ self.workspace_name = workspace_name if api_config: self.config = api_config else: self.config = SlackApiConfig() secret_reader = SecretReader(settings=settings) slack_token = secret_reader.read(token) self._sc = WebClient(token=slack_token, timeout=self.config.timeout) self._configure_client_retry() self._results: Dict[str, Any] = {} self.channel = channel self.chat_kwargs = chat_kwargs if init_usergroups: self._initiate_usergroups() def _configure_client_retry(self) -> None: """ Add retry handlers in addition to the defaults provided by the Slack client. """ rate_limit_handler = RateLimitErrorRetryHandler( max_retry_count=self.config.max_retries) server_error_handler = ServerErrorRetryHandler( max_retry_count=self.config.max_retries) self._sc.retry_handlers.append(rate_limit_handler) self._sc.retry_handlers.append(server_error_handler) def chat_post_message(self, text: str) -> None: """ Sends a message to a channel. :param text: message to send to channel :raises ValueError: when Slack channel wasn't provided :raises slack_sdk.errors.SlackApiError: if unsuccessful response from Slack API """ if not self.channel: raise ValueError('Slack channel name must be provided when ' 'posting messages.') self._sc.chat_postMessage(channel=self.channel, text=text, **self.chat_kwargs) def describe_usergroup(self, handle): usergroup = self.get_usergroup(handle) description = usergroup['description'] user_ids = usergroup.get('users', []) users = self.get_users_by_ids(user_ids) channel_ids = usergroup['prefs']['channels'] channels = self.get_channels_by_ids(channel_ids) return users, channels, description def get_usergroup_id(self, handle): usergroup = self.get_usergroup(handle) return usergroup['id'] def _initiate_usergroups(self) -> None: """ Initiates usergroups list. :raises slack_sdk.errors.SlackApiError: if unsuccessful response from Slack API """ result = self._sc.usergroups_list(include_users=True) self.usergroups = result['usergroups'] def get_usergroup(self, handle): usergroup = [g for g in self.usergroups if g['handle'] == handle] if len(usergroup) != 1: raise UsergroupNotFoundException(handle) [usergroup] = usergroup return usergroup def update_usergroup(self, id: str, channels_list: Sequence[str], description: str) -> None: """ Update an existing usergroup. :param id: encoded usergroup ID :param channels_list: encoded channel IDs that the usergroup uses by default :param description: short description of the usergroup :raises slack_sdk.errors.SlackApiError: if unsuccessful response from Slack API """ self._sc.usergroups_update(usergroup=id, channels=channels_list, description=description) def update_usergroup_users(self, id: str, users_list: Sequence[str]) -> None: """ Update the list of users for a usergroup. :param id: encoded usergroup ID :param users_list: encoded user IDs that represents the entire list of users for the usergroup :raises slack_sdk.errors.SlackApiError: if unsuccessful response from Slack API """ # since Slack API does not support empty usergroups # we can trick it by passing a deleted user if len(users_list) == 0: users_list = [self.get_random_deleted_user()] try: self._sc.usergroups_users_update(usergroup=id, users=users_list) except SlackApiError as e: # Slack can throw an invalid_users error when emptying groups, but # it will still empty the group (so this can be ignored). if e.response['error'] != 'invalid_users': raise def get_random_deleted_user(self): for user_id, user_data in self._get('users').items(): if user_data['deleted'] is True: return user_id logging.error('could not find a deleted user, ' + 'empty usergroup will not work') return '' def get_user_id_by_name(self, user_name: str) -> str: """ Get user id from their username. :param user_name: Slack user name :return: encoded user ID (ex. W012A3CDE) :raises slack_sdk.errors.SlackApiError: if unsuccessful response from Slack API :raises UserNotFoundException: if the Slack user is not found """ config = get_config() mail_address = config['smtp']['mail_address'] try: result = self._sc.users_lookupByEmail( email=f"{user_name}@{mail_address}") except SlackApiError as e: if e.response['error'] == 'users_not_found': raise UserNotFoundException(e.response['error']) else: raise return result['user']['id'] def get_channels_by_names(self, channels_names): return { k: v['name'] for k, v in self._get('channels').items() if v['name'] in channels_names } def get_channels_by_ids(self, channels_ids): return { k: v['name'] for k, v in self._get('channels').items() if k in channels_ids } def get_users_by_names(self, user_names): return { k: v['name'] for k, v in self._get('users').items() if v['name'] in user_names } def get_users_by_ids(self, users_ids): return { k: v['name'] for k, v in self._get('users').items() if k in users_ids } def _get(self, resource: str) -> Dict[str, Any]: """ Get Slack resources by type. This method uses a cache to ensure that each resource type is only fetched once. :param resource: resource type :return: data from API call """ result_key = 'members' if resource == 'users' else resource api_key = 'conversations' if resource == 'channels' else resource results = {} additional_kwargs: Dict[str, Union[str, int]] = {'cursor': ''} if resource in self._results: return self._results[resource] if self.config: method_config = self.config.get_method_config(f'{api_key}.list') if method_config: additional_kwargs.update(method_config) while True: result = self._sc.api_call("{}.list".format(api_key), http_verb='GET', params=additional_kwargs) for r in result[result_key]: results[r['id']] = r cursor = result['response_metadata']['next_cursor'] if cursor == '': break additional_kwargs['cursor'] = cursor self._results[resource] = results return results
exit() if args.list: post_format.update(post_format_list) elif args.ranking: post_format.update(post_format_ranking) for k, v in post_format.items(): globals()[k] = v if args.slacktoken: token = args.slacktoken else: with open(slacktoken_file_path, 'r') as f: token = f.readline().rstrip() web_client = WebClient(token=token) channel_id = get_channel_id(web_client, channel_name) my_id = web_client.api_call('auth.test')['user_id'] logins = set() if os.path.exists(excluded_members_file_path): with open(excluded_members_file_path, 'r') as f: lines = f.readlines() for line in lines: excluded_members.add(line.rstrip().split()[1]) members_info = web_client.api_call('users.list')['members'] name = dict() for member in members_info: display_name = member['profile']['display_name'] real_name = member['profile']['real_name'] if display_name: name[member['id']] = display_name else: