failed = 'failed' def decode(s): return b64decode(bytes(s, 'utf-8')).decode('utf-8') @click.command() @click.argument('channel') @click.argument('case') @click.argument('status') @click.option('--kv', multiple=True) # simple kv @click.option('--b64encodedkvs', default='') # complex kv def send_message(channel, case, status, kv, b64encodedkvs): status = Status(status) client = WebClient(token=os.getenv('SLACK_BOT_TOKEN')) fields = [] fields.append(('status', f'{status.value}')) fields.append(('time', f'{datetime.now()}')) if status is Status.running: color = '#268bd2' # blue, copied from solorized theme title = f"Test case `{case}` {status.value} 🙏" else: if status is Status.failed: color = 'danger' else: color = 'good' title = f"Test case `{case}` {status.value} --- {status.value}" if kv:
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"])
import schedule import time import json from decouple import config from slack_sdk import WebClient from slack_sdk.errors import SlackApiError import requests # from pprint import pprint TOKEN = config('TOKEN') channel = '#remote-report' client = WebClient(token=TOKEN) def make_quote(): while True: try: response = requests.get( 'https://quote-garden.herokuapp.com/api/v3/quotes/random' ).json() except json.decoder.JSONDecodeError: continue else: quote_text = response.get('data')[0].get('quoteText') quote_author = response.get('data')[0].get('quoteAuthor') if response.get('quoteAuthor') == '': quote_author = 'Anonymous' return f'"{quote_text}" - {quote_author}'
from slack_sdk.errors import SlackApiError from slack_print import SlackPrint host_system = platform.uname() print(f'{"Analyzing system internals"}') for i in tqdm(host_system): time.sleep(1) with open("sysinfo.txt", "w") as text_file: text_file.write(f"System: {host_system.system}\n") text_file.write(f"Node Name: {host_system.node}\n") text_file.write(f"Release: {host_system.release}\n") text_file.write(f"Version: {host_system.version}\n") text_file.write(f"Machine: {host_system.machine}\n") text_file.write(f"Processor: {host_system.processor}\n") # Run SLACK_BOT_TOKEN python3 <script_name.py> client = WebClient(token=os.environ["SLACK_BOT_TOKEN"]) try: filepath = "./sysinfo.txt" sp = SlackPrint("SLACK_TOKEN", '#test') # Enter the slack token here sp.upload('sysinfo.txt') except SlackApiError as e: assert e.response["ok"] is False assert e.response["error"] print(f"got an error: {e.response['error']}") #Done
SubsubheaderBlock, TextBlock, ) from notion.client import NotionClient from slack_sdk import WebClient from slack_sdk.errors import SlackApiError # .envファイルを読み込み、環境変数として扱う dotenv_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), ".env") load_dotenv(dotenv_path) SLACK_TOKEN = os.environ.get("OAuth_Access_Token") NOTION_TOKEN = os.environ.get("token_v2") TOP_PAGE_URL = os.environ.get("top_page") # 各種サービスに接続するインスタンス slack_client = WebClient(token=SLACK_TOKEN) notion_client = NotionClient(token_v2=NOTION_TOKEN) channel = "#bleeeeeefing" today = datetime.date.today() # Bleeeeeefingのページを管理しているトップページ top_page = notion_client.get_block(TOP_PAGE_URL) def _str_to_date(date: str) -> datetime.date: """ 例) "20210214" → datetime.date(2021, 2, 14) """ tdatetime = datetime.datetime.strptime(date, "%Y%m%d")
import os from slack_sdk import WebClient from slack_sdk.webhook import WebhookClient from slack_sdk.errors import SlackApiError client = WebClient(token=os.environ['SLACK_BOT_TOKEN']) # Initialize Slack WebHook webhook = WebhookClient(os.environ['WEBHOOK_URL']) def SendMessage(message): '''Send a simple text message to the #garden channel.''' response = webhook.send(text=message) assert response.status_code == 200 def UploadFile(filepath, filename): ''' Upload a file on disk (at filepath) to Slack. Filename changes the target name in the Slack Channel. Does not relate to the filename on disk. ''' try: response = client.files_upload(channels='garden', file=filepath, title=filename) assert response["file"] # the uploaded file except SlackApiError as e: # You will get a SlackApiError if "ok" is False assert e.response["ok"] is False assert e.response["error"] # str like 'invalid_auth', 'channel_not_found' print(f"Got an error: {e.response['error']}")
def sync( num_items: int, num_pages: int, orders_per_page: int, request_backoff_seconds: int, dry_run: bool, ) -> None: """Sync users from Shopify to Cognito""" shopify_key = os.environ.get("SHOPIFY_KEY") shopify_pass = os.environ.get("SHOPIFY_PASS") transport = AIOHTTPTransport( url= f"https://{shopify_key}:{shopify_pass}@tstvhq.myshopify.com/admin/api/2021-04/graphql.json" ) shopify_client = Client(transport=transport, fetch_schema_from_transport=True) aws_client = boto3.client("cognito-idp") user_pool_id = os.getenv("AWS_COGNITO_USER_POOL_ID") slack_client = WebClient(token=os.environ.get("SLACK_BOT_TOKEN")) orders = get_shopify_orders(shopify_client, num_items, num_pages, orders_per_page, request_backoff_seconds) current_users = list(get_aws_users(aws_client, user_pool_id)) new_users: Set[str] = set() user_groups: Dict[str, Set[str]] = {} for order in orders: if len(order.product_handles.intersection(SYNC_MAP.keys())) > 0: if order.email is None: print("Ignoring order with empty email") continue if order.email not in current_users: new_users.add(order.email.lower()) if order.email not in user_groups.keys(): user_groups[order.email] = set() groups = user_groups[order.email] for handle in order.product_handles: if handle in SYNC_MAP.keys(): groups.add(SYNC_MAP[handle]) print(f"Adding {len(new_users)} new users") print(f"Adding {len(user_groups.keys())} users to groups") if dry_run: return for user in new_users: print(f"Creating user {user}") create_aws_user(aws_client, user_pool_id, user) sleep(1) for user, groups in user_groups.items(): for group in groups: print(f"Adding {user} to {group}") add_aws_user_to_group(aws_client, user_pool_id, user, group) sleep(1) send_slack_message( slack_client, f"Created {len(new_users)} new users and added {len(user_groups.keys())} users to groups", )
def slack_post(channel, thread=None, text=None, content=None, username=None, icon_url=None, attachment=None): """ Post a message on Slack The `text` parameter is not required when the `content` parameter is provided, however including it is still highly recommended. :param channel: The identifier of the Slack conversation to post to :param thread: The timestamp of another message to post this message as a reply to :param text: Message text (Formatting: https://api.slack.com/reference/surfaces/formatting) :param content: List of valid blocks data (https://api.slack.com/block-kit) :param username: Name displayed by the bot :param icon_url: The URL to an image / icon to display next to the message (profile picture) :param attachment: Dictionary with file details - {'name': 'Example File', 'filepath': '/media/slack/example.pdf'} :returns: Response object (Dictionary) """ if not settings.SLACK_TOKEN: return {'ok': False, 'error': 'config_error'} client = WebClient(token=settings.SLACK_TOKEN) if attachment: filename = attachment['filepath'].split('/')[-1] return upload(attachment['filepath'], filename, attachment['name'], text, channel) if content: try: if username: response = client.chat_postMessage(channel=channel, thread_ts=thread, blocks=content, text=text, username=username, icon_url=icon_url) else: response = client.chat_postMessage(channel=channel, thread_ts=thread, blocks=content, text=text) assert response['ok'] is True return {'ok': True, 'message': response['message']} except SlackApiError as e: assert e.response['ok'] is False return e.response elif text: try: if username: response = client.chat_postMessage(channel=channel, thread_ts=thread, text=text, username=username, icon_url=icon_url) else: response = client.chat_postMessage(channel=channel, thread_ts=thread, text=text) assert response['ok'] is True return {'ok': True, 'message': response['message']} except SlackApiError as e: assert e.response['ok'] is False return e.response elif not content and not text: return {'ok': False, 'error': 'no_text'}
def delete_file(id): client = WebClient(token=settings.SLACK_TOKEN) response = client.files_delete(file=id) return response['ok']
def _send_slack_message(channel, message_text): sc = WebClient(token=BOT_USER_API_KEY) sc.chat_postMessage(channel=channel, text=message_text)
import os from slack_sdk import WebClient from slack_sdk.errors import SlackApiError import time client = WebClient( token='xoxb-878537608886-1683457705654-Vx4DSD1U2yGuIc2GCxmpVwhI') def send_message_to_slack(content): try: response = client.chat_postMessage(channel='梦幻', text=content) # assert response["message"]["text"] == "Hello world!" # print(response) except SlackApiError as e: # You will get a SlackApiError if "ok" is False assert e.response["ok"] is False assert e.response[ "error"] # str like 'invalid_auth', 'channel_not_found' print(f"Got an error: {e.response['error']}") time.sleep(10) # send_message_to_slack('111233哈哈')
import os from slack_sdk import WebClient from slack_sdk.errors import SlackApiError client = WebClient( token='') # blockchain channel 에서 send message def sendMessage(message): try: response = client.chat_postMessage( channel='#blockchain', text=message) assert response["message"]["text"] == message except SlackApiError as e: # You will get a SlackApiError if "ok" is False assert e.response["ok"] is False # str like 'invalid_auth', 'channel_not_found' assert e.response["error"] print(f"Got an error: {e.response['error']}") # message 작성 message = "[ENJKRW] UPBIT(500원 100개 매수) BINANCE(400원 100개 매도)" # sendMessgae 실행 sendMessage(message)
def slack_send_message(): client = WebClient(token=SLACK_TOKEN) try: response = client.chat_postMessage(channel="airflowtask33", text="Hello from your app! :tada:") except SlackApiError as e: assert e.response["error"] # str like 'invalid_auth', 'channel_not_found'
def main() -> None: token = input("User OAuth Token: ") init_web_client(token) # only for post message bot_token = input("Bot User OAuth Token: ") bot_client = WebClient(token=bot_token) public_channel_map = get_public_channel_map() if public_channel_map is None: sys.exit(1) while True: ranking_type = input("Choose ranking type [top/unused]: ") if ranking_type not in ["top", "unused"]: print("Invalid ranking type. Try again.") continue if ranking_type == "top": ranking_limit = input("Choose ranking limit (default: 10): ") else: ranking_limit = input("Choose ranking limit (default: 0): ") if ranking_limit != "" and not ranking_limit.isnumeric(): print("Invalid ranking limit. Need to input number. Try again.") continue else: default_limit = 10 if ranking_type == "top" else 0 ranking_limit = int(ranking_limit or default_limit) break while True: if ranking_type == "top": target_channel = input( "Channel name to survey (default: all channel): " ) # noqa: E501 else: confirm_reccomended = input( "Surveying all channel is reccomended for unused ranking. Are you sure? [Y/n]: " ) # noqa: E501 if confirm_reccomended == "n": target_channel = input( "Channel name to survey (default: all channel): " ) # noqa: E501 else: target_channel = "" if ranking_type == "top" and target_channel == "": confirm = input( "It takes long time to survey all channels. Continue? [y/N]: " ) # noqa: E501 if confirm != "y": continue else: print("continue.") if target_channel != "" and target_channel not in public_channel_map.keys( ): print("Error: invalid channel name. Try again.") continue break if ranking_type == "top": while True: post_channel_name = input("Channel name to post message: ") if post_channel_name not in public_channel_map.keys(): print("Error: invalid channel name. Try again.") continue break while True: emoji_type = input( "Choose emoji type [custom/all] (default: all): " ) # noqa: E501 if emoji_type not in ["", "custom", "all"]: print( "Error: invalid emoji type. Choose [custom/all]. Try again." ) # noqa: E501 continue break else: # Don't post to slack cause unused ranking message is too log to post post_channel_name = "" # Only custom is available for unused ranking emoji_type = "custom" print("\nstart surveying...\n") if target_channel == "": if emoji_type == "custom": result = get_custom_emoji_count_in_all_public_channel() else: result = get_emoji_count_in_all_public_channel() else: if emoji_type == "custom": result = get_custom_emoji_count(target_channel) else: result = get_emoji_count(target_channel) if result is None: print("Failed to get count result.") sys.exit(1) # message header message_header = "" if ranking_type == "top": message_header += f"*Emojiランキング* Top {ranking_limit}\n\n" else: message_header += f"*使っていないEmojiランキング* Under {ranking_limit}\n\n" message_header += "集計範囲: " if target_channel == "": message_header += "すべてのパブリックチャンネル(log系チャンネルを除く)\n" else: message_header += f"<#{public_channel_map[target_channel]}>\n" message_header += "集計対象: " message_header += "カスタムEmojiのみ\n" if emoji_type == "custom" or ranking_type == "unused" else "すべてのEmoji\n" message_header += f"集計期間: {OLDEST.strftime(DATE_FORMAT)} ~ {LATEST.strftime(DATE_FORMAT)}\n" message_header += "\n" # sort and create message if ranking_type == "top": sorted_result = get_top_emoji_count(result, ranking_limit) message = message_header + get_post_message_by_sorted_count( sorted_result) post_message(bot_client, post_channel_name, message) # post deletable message # post_message(client, post_channel_name, message) else: unused_custom_emojis = get_unused_custom_emojis(result, ranking_limit) message = message_header + get_post_message_by_unused_custom_emojis( unused_custom_emojis) # Don't post to slack cause unused ranking has too long message print(f"--------\n\n{message}\n\n--------") print("\nend surveying.\n")
def set_token(self): if os.path.exists(".env"): load_dotenv(verbose=True) self.token = os.environ["SLACK_TOKEN"] self.client = WebClient(token=self.token)
import sys import logging import math # Configure AWS credentials config = configparser.ConfigParser() config.read('../config/credentials.ini') host = config['aws']['host'] port = int(config['aws']['port']) user = config['aws']['user'] password = config['aws']['password'] db = sys.argv[1] # Use this for the multi-region automated update # Set Slack token key = sys.argv[2] # Use this for the multi-region automated update slack = WebClient(token=key) #Define AWS Database connection criteria mydb = pymysql.connect(host=host, port=port, user=user, password=password, db=db, charset='utf8mb4', cursorclass=pymysql.cursors.DictCursor) # Set epoch and yesterday's timestamp for datetime calculations epoch = datetime(1970, 1, 1) yesterday = datetime.now() - timedelta(days=1) oldest = yesterday.timestamp() today = datetime.now()
def create_web_client(token: Optional[str] = None) -> WebClient: return WebClient( token=token, user_agent_prefix=f"Bolt/{bolt_version}", )
def slack_app(): if not verify_slack_request( signing_secret=signing_secret, request_body=request.get_data(), timestamp=request.headers.get("X-Slack-Request-Timestamp"), signature=request.headers.get("X-Slack-Signature")): return make_response("invalid request", 403) if "command" in request.form \ and request.form["command"] == "/do-something": trigger_id = request.form["trigger_id"] try: team_id = request.form["team_id"] bot_token = database.find_bot_token(team_id) logger.debug(f"token: {bot_token}") if not bot_token: return make_response("Please install this app first!", 200) client = WebClient(token=bot_token) response = client.views_open( trigger_id=trigger_id, view={ "type": "modal", "callback_id": "modal-id", "title": { "type": "plain_text", "text": "Awesome Modal" }, "submit": { "type": "plain_text", "text": "Submit" }, "close": { "type": "plain_text", "text": "Cancel" }, "blocks": [ { "type": "input", "block_id": "b-id", "label": { "type": "plain_text", "text": "Input label", }, "element": { "action_id": "a-id", "type": "plain_text_input", } } ] } ) return make_response("", 200) except SlackApiError as e: code = e.response["error"] return make_response(f"Failed to open a modal due to {code}", 200) elif "payload" in request.form: payload = json.loads(request.form["payload"]) if payload["type"] == "view_submission" \ and payload["view"]["callback_id"] == "modal-id": submitted_data = payload["view"]["state"]["values"] print(submitted_data) # {'b-id': {'a-id': {'type': 'plain_text_input', 'value': 'your input'}}} return make_response("", 200) return make_response("", 404)
def send_message(message: str) -> None: """Send a message to Slack""" client = WebClient(token=os.environ.get("SLACK_BOT_TOKEN")) send_slack_message(client, message)
def slack_api_call(token, method, params): client = WebClient(token=token) response = client.api_call(api_method=method, params=params) print(response) return response
class TestViewSubmission: signing_secret = "secret" valid_token = "xoxb-valid" mock_api_server_base_url = "http://localhost:8888" signature_verifier = SignatureVerifier(signing_secret) web_client = WebClient( token=valid_token, base_url=mock_api_server_base_url, ) def setup_method(self): self.old_os_env = remove_os_env_temporarily() setup_mock_web_api_server(self) def teardown_method(self): cleanup_mock_web_api_server(self) restore_os_env(self.old_os_env) def generate_signature(self, body: str, timestamp: str): return self.signature_verifier.generate_signature( body=body, timestamp=timestamp, ) def build_headers(self, timestamp: str, body: str): return { "content-type": ["application/x-www-form-urlencoded"], "x-slack-signature": [self.generate_signature(body, timestamp)], "x-slack-request-timestamp": [timestamp], } def build_valid_request(self) -> BoltRequest: timestamp = str(int(time())) return BoltRequest( body=raw_body, headers=self.build_headers(timestamp, raw_body) ) def test_mock_server_is_running(self): resp = self.web_client.api_test() assert resp != None def test_success(self): app = App( client=self.web_client, signing_secret=self.signing_secret, ) app.view("view-id")(simple_listener) request = self.build_valid_request() response = app.dispatch(request) assert response.status == 200 assert self.mock_received_requests["/auth.test"] == 1 def test_success_2(self): app = App( client=self.web_client, signing_secret=self.signing_secret, ) app.view_submission("view-id")(simple_listener) request = self.build_valid_request() response = app.dispatch(request) assert response.status == 200 assert self.mock_received_requests["/auth.test"] == 1 def test_process_before_response(self): app = App( client=self.web_client, signing_secret=self.signing_secret, process_before_response=True, ) app.view("view-id")(simple_listener) request = self.build_valid_request() response = app.dispatch(request) assert response.status == 200 assert self.mock_received_requests["/auth.test"] == 1 def test_failure(self): app = App( client=self.web_client, signing_secret=self.signing_secret, ) request = self.build_valid_request() response = app.dispatch(request) assert response.status == 404 assert self.mock_received_requests["/auth.test"] == 1 app.view("view-idddd")(simple_listener) response = app.dispatch(request) assert response.status == 404 assert self.mock_received_requests["/auth.test"] == 1 def test_failure_2(self): app = App( client=self.web_client, signing_secret=self.signing_secret, ) request = self.build_valid_request() response = app.dispatch(request) assert response.status == 404 assert self.mock_received_requests["/auth.test"] == 1 app.view_submission("view-idddd")(simple_listener) response = app.dispatch(request) assert response.status == 404 assert self.mock_received_requests["/auth.test"] == 1
from settings import Config, Session from sendgrid import SendGridAPIClient from sendgrid.helpers.mail import Mail from email_validator import validate_email from twilio.rest import Client import phonenumbers from slack_sdk import WebClient from urllib.request import urlopen logging.basicConfig() logging.getLogger('notifications_manager').setLevel(logging.INFO) email_client = SendGridAPIClient(Config['notifications']['sendgrid_api_key']) sms_client = Client(Config['notifications']['twilio_sid'], Config['notifications']['twilio_auth_token']) slack_client = WebClient(token=Config['notifications']['slack_bot_auth_token']) @validate_arguments(config=dict(arbitrary_types_allowed=True)) def send_notification(recipient: str, message: str, channel: NotificationChannel, scheduled_send_date: datetime = None, subject=None): notification = Notification(recipient=recipient, subject=subject, message=message, channel=channel, scheduled_send_date=scheduled_send_date) db = Session()
def display_karma_leaderboards(self) -> Tuple[str, str, str]: """Prints rudimentary user and thing leaderboards. Returns: A message, if applicable, a string representation of the user leaderboard, and a string representation of the thing leaderboard. """ Row = namedtuple("Row", "name pluses minuses net_score") try: with open(self.karma_file_path, "r", encoding="utf-8") as karma_file: cur_karma = json.load(karma_file) user_table = [] thing_table = [] for item in cur_karma: name = item["name"] pluses = item["pluses"] minuses = item["minuses"] delta = pluses - minuses if name.startswith("<@"): name = name.lstrip("<@").rstrip(">") user_table.append(Row(name, pluses, minuses, delta)) elif name.startswith( "<!"): # Special case for @everyone, @channel, @here name = name.lstrip("<!").rstrip(">") user_table.append(Row(name, pluses, minuses, delta)) else: thing_table.append(Row(name, pluses, minuses, delta)) assert user_table or thing_table except (ValueError, AssertionError): # Empty file or no file present self.logger.exception( "Empty karma file or no file present, return.") return ("No karma yet!", "", "") try: web_client = WebClient(token=os.environ.get("SLACK_BOT_TOKEN")) request = web_client.users_list() ids_to_names = {} if request["ok"]: for member in request["members"]: try: name = member.get("real_name") or member.get("name") assert name ids_to_names[member["id"]] = name except AssertionError: self.logger.debug("Unable to get name for id %s", member["id"]) # Convert user IDs to actual names usr_table = [] for row in user_table: if row.name in ids_to_names: name = ids_to_names[row.name] usr_table.append( Row(name, row.pluses, row.minuses, row.net_score)) else: usr_table.append(row) usr_table = sorted(usr_table, reverse=True, key=lambda x: x.net_score)[:10] thing_table = sorted(thing_table, reverse=True, key=lambda x: x.net_score)[:10] headers = ["Name", "Pluses", "Minuses", "Net Score"] users = tabulate([list(row) for row in usr_table], headers, tablefmt="github") things = tabulate([list(row) for row in thing_table], headers, tablefmt="github") return ( "", f"User leaderboard:\n ```{users}```", f"Thing leaderboard:\n ```{things}```", ) except SlackApiError as api_err: self.logger.error("Failed to generate leaderboard due to %s", api_err) return ("", "", "")
class TestErrorHandler: signing_secret = "secret" valid_token = "xoxb-valid" mock_api_server_base_url = "http://localhost:8888" signature_verifier = SignatureVerifier(signing_secret) web_client = WebClient( token=valid_token, base_url=mock_api_server_base_url, ) def setup_method(self): self.old_os_env = remove_os_env_temporarily() setup_mock_web_api_server(self) def teardown_method(self): cleanup_mock_web_api_server(self) restore_os_env(self.old_os_env) # ---------------- # utilities # ---------------- def generate_signature(self, body: str, timestamp: str): return self.signature_verifier.generate_signature( body=body, timestamp=timestamp, ) def build_headers(self, timestamp: str, body: str): return { "content-type": ["application/x-www-form-urlencoded"], "x-slack-signature": [self.generate_signature(body, timestamp)], "x-slack-request-timestamp": [timestamp], } def build_valid_request(self) -> BoltRequest: body = { "type": "block_actions", "user": { "id": "W111", }, "api_app_id": "A111", "token": "verification_token", "trigger_id": "111.222.valid", "team": { "id": "T111", }, "channel": {"id": "C111", "name": "test-channel"}, "response_url": "https://hooks.slack.com/actions/T111/111/random-value", "actions": [ { "action_id": "a", "block_id": "b", "text": {"type": "plain_text", "text": "Button"}, "value": "click_me_123", "type": "button", "action_ts": "1596530385.194939", } ], } raw_body = f"payload={quote(json.dumps(body))}" timestamp = str(int(time.time())) return BoltRequest( body=raw_body, headers=self.build_headers(timestamp, raw_body) ) # ---------------- # tests # ---------------- def test_lazy(self): def just_ack(ack): ack() def async1(say): time.sleep(0.3) say(text="lazy function 1") def async2(say): time.sleep(0.5) say(text="lazy function 2") app = App( client=self.web_client, signing_secret=self.signing_secret, ) app.action("a")( ack=just_ack, lazy=[async1, async2], ) request = self.build_valid_request() response = app.dispatch(request) assert response.status == 200 time.sleep(1) # wait a bit assert self.mock_received_requests["/chat.postMessage"] == 2 def test_lazy_class(self): def just_ack(ack): ack() class LazyClass: def __call__(self, say): time.sleep(0.3) say(text="lazy function 1") def async2(say): time.sleep(0.5) say(text="lazy function 2") app = App( client=self.web_client, signing_secret=self.signing_secret, ) app.action("a")( ack=just_ack, lazy=[LazyClass(), async2], ) request = self.build_valid_request() response = app.dispatch(request) assert response.status == 200 time.sleep(1) # wait a bit assert self.mock_received_requests["/chat.postMessage"] == 2
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 post_slack(text, param): client = WebClient(token=SLACK_TOKEN) response = client.chat_postMessage(channel=SLACK_CHANNEL, text=text, thread_ts=param['ts'])
def __init__(self, token): self.client = WebClient(token=token)
# Post updates to #envoy-maintainer-oncall unassigned_prs = maintainers_and_messages['unassigned'] if unassigned_prs: try: response = client.chat_postMessage( channel='#envoy-maintainer-oncall', text=( "*'Unassigned' PRs* (PRs with no maintainer assigned)\n%s" % unassigned_prs)) response = client.chat_postMessage( channel='#envoy-maintainer-oncall', text=("*Stalled PRs*\n\n%s" % out_slo_prs)) except SlackApiError as e: print("Unexpected error %s", e.response["error"]) if __name__ == '__main__': maintainers_and_messages, shephards_and_messages, stalled_prs = track_prs() SLACK_BOT_TOKEN = os.getenv('SLACK_BOT_TOKEN') if not SLACK_BOT_TOKEN: print( 'Missing SLACK_BOT_TOKEN: please export token from https://api.slack.com/apps/A023NPQQ33K/oauth?' ) sys.exit(1) client = WebClient(token=SLACK_BOT_TOKEN) post_to_oncall(client, maintainers_and_messages['unassigned'], stalled_prs) post_to_assignee(client, shephards_and_messages, API_REVIEWERS) post_to_assignee(client, maintainers_and_messages, MAINTAINERS)
def setUp(self): setup_mock_web_api_server(self) self.web_client = WebClient( token="xoxb-api_test", base_url="http://localhost:8888", )
def make_slack_on_pipeline_failure_sensor( channel: str, slack_token: str, text_fn: Callable[[PipelineFailureSensorContext], str] = _default_failure_message_text_fn, blocks_fn: Optional[Callable[[PipelineFailureSensorContext], List[Dict]]] = None, pipeline_selection: Optional[List[str]] = None, name: Optional[str] = None, dagit_base_url: Optional[str] = None, default_status: DefaultSensorStatus = DefaultSensorStatus.STOPPED, ): """Create a sensor on pipeline failures that will message the given Slack channel. Args: channel (str): The channel to send the message to (e.g. "#my_channel") slack_token (str): The slack token. Tokens are typically either user tokens or bot tokens. More in the Slack API documentation here: https://api.slack.com/docs/token-types text_fn (Optional(Callable[[PipelineFailureSensorContext], str])): Function which takes in the ``PipelineFailureSensorContext`` and outputs the message you want to send. Defaults to a text message that contains error message, pipeline name, and run ID. The usage of the `text_fn` changes depending on whether you're using `blocks_fn`. If you are using `blocks_fn`, this is used as a fallback string to display in notifications. If you aren't, this is the main body text of the message. It can be formatted as plain text, or with mrkdwn. See more details in https://api.slack.com/methods/chat.postMessage#text_usage blocks_fn (Callable[[PipelineFailureSensorContext], List[Dict]]): Function which takes in the ``PipelineFailureSensorContext`` and outputs the message blocks you want to send. See information about Blocks in https://api.slack.com/reference/block-kit/blocks pipeline_selection (Optional[List[str]]): Names of the pipelines that will be monitored by this failure sensor. Defaults to None, which means the alert will be sent when any pipeline in the repository fails. name: (Optional[str]): The name of the sensor. Defaults to "slack_on_pipeline_failure". dagit_base_url: (Optional[str]): The base url of your Dagit instance. Specify this to allow messages to include deeplinks to the failed pipeline run. default_status (DefaultSensorStatus): Whether the sensor starts as running or not. The default status can be overridden from Dagit or via the GraphQL API. Examples: .. code-block:: python slack_on_pipeline_failure = make_slack_on_pipeline_failure_sensor( "#my_channel", os.getenv("MY_SLACK_TOKEN") ) @repository def my_repo(): return [my_pipeline + slack_on_pipeline_failure] .. code-block:: python def my_message_fn(context: PipelineFailureSensorContext) -> str: return "Pipeline {pipeline_name} failed! Error: {error}".format( pipeline_name=context.pipeline_run.pipeline_name, error=context.failure_event.message, ) slack_on_pipeline_failure = make_slack_on_pipeline_failure_sensor( channel="#my_channel", slack_token=os.getenv("MY_SLACK_TOKEN"), message_fn=my_message_fn, dagit_base_url="http://mycoolsite.com", ) """ slack_client = WebClient(token=slack_token) @pipeline_failure_sensor(name=name, pipeline_selection=pipeline_selection, default_status=default_status) def slack_on_pipeline_failure(context: PipelineFailureSensorContext): blocks, main_body_text = _build_slack_blocks_and_text( context=context, text_fn=text_fn, blocks_fn=blocks_fn, dagit_base_url=dagit_base_url) slack_client.chat_postMessage(channel=channel, blocks=blocks, text=main_body_text) return slack_on_pipeline_failure