Beispiel #1
0
    def custom_slack_on_pipeline_failure(
            context: PipelineFailureSensorContext):

        base_url = "http://localhost:3000"

        slack_client = WebClient(
            token=os.environ["SLACK_DAGSTER_ETL_BOT_TOKEN"])

        run_page_url = f"{base_url}/instance/runs/{context.pipeline_run.run_id}"
        channel = "#yuhan-test"
        message = "\n".join([
            f'Pipeline "{context.pipeline_run.pipeline_name}" failed.',
            f"error: {context.failure_event.message}",
            f"mode: {context.pipeline_run.mode}",
            f"run_page_url: {run_page_url}",
        ])

        slack_client.chat_postMessage(
            channel=channel,
            blocks=[{
                "type": "section",
                "text": {
                    "type": "mrkdwn",
                    "text": message
                }
            }],
        )
Beispiel #2
0
 def __init__(self):
     _settings, _ = import_settings()
     slack_api_token = _settings.get('SLACK_API_TOKEN', None)
     http_proxy = _settings.get('HTTP_PROXY', None)
     self.rtm_client = RTMClient(token=slack_api_token, proxy=http_proxy)
     self.web_client = WebClient(token=slack_api_token, proxy=http_proxy)
     self._bot_info = {}
     self._users = {}
     self._channels = {}
Beispiel #3
0
    def __init__(self, token: str = None, default_channel: str = None):

        # Rely on system token if one wasn't passed
        if not token:
            token = Slack_Settings.APP_SLACK_TOKEN

        # Create internal client to serve as an adapter for
        self._client = WebClient(token=token)

        # Set the default channel
        self.default_channel = Slack_Settings.APP_SLACK_LOGGING_CHANNEL if not default_channel else default_channel
Beispiel #4
0
def upload_images(token: str, channel: str, filepath: str, description: str):
    client = WebClient(token=token)
    with _open(filepath, mode="rb") as f:
        if isinstance(f, io.BytesIO):
            image_type = imghdr.what(f)
        else:
            raise ValueError(f"'{filepath}' is not supported format")
        if image_type not in SUPPORTED_IMAGES:
            raise ValueError(f"'{filepath}' is not supported format")
        client.files_upload(file=f,
                            channels=channel,
                            initial_comment=description)
    def post_message_to_slack(self,
                              text: str,
                              blocks: Any = None,
                              use_conversation_threads: bool = True) -> Any:
        """
        Posts a message to Slack
        :param text: message to post.  Can be markdown.
        :param blocks: (Optional) blocks to post
        :param use_conversation_threads: whether to send messages as reply to first message
        :return: response from Slack
        """
        if not text:
            return None

        if (self.wait_till_datetime is not None
                and self.wait_till_datetime > datetime.utcnow()):
            return None

        try:
            web = WebClient(token=self.slack_token)
            response: SlackResponse = web.chat_postMessage(
                text=text,
                channel=self.slack_channel,
                thread_ts=self.slack_thread,
                icon_url=self.slack_icon_url,
                username=self.slack_user_name,
                blocks=json.dumps(blocks) if blocks else None,
            )

            if not self.slack_thread and use_conversation_threads:
                if (response.status_code == 200 and response.data
                        and "ts" in response.data):
                    self.slack_thread = response.data["ts"]  # type: ignore
            self.wait_till_datetime = None  # clear this on success
            return response
        except SlackApiError as e:
            logger.warning(f"Slack API Error: {e.response['error']}")
            if e.response.status_code == 429:
                # The `Retry-After` header will tell you how long to wait before retrying
                delay_in_seconds: int = int(e.response.headers["Retry-After"])
                logger.warning(
                    f"Rate limited. Retrying in {delay_in_seconds} seconds")
                self.wait_till_datetime = datetime.utcnow() + timedelta(
                    seconds=delay_in_seconds)
            return None
        except Exception as e:
            logger.warning(f"Unknown error calling Slack API: {e}")
            return None
Beispiel #6
0
class KolgaSlackPlugin(PluginBase):

    name = "slack"
    verbose_name = "Kolga Slack Plugin"
    version = 0.1

    # Environment variables
    SLACK_TOKEN: str
    SLACK_CHANNEL: str

    def __init__(self, env: Env) -> None:
        self.required_variables = [("SLACK_TOKEN", env.str),
                                   ("SLACK_CHANNEL", env.str)]
        self.configure(env)
        self.client = WebClient(self.SLACK_TOKEN)

    @hookimpl
    def project_deployment_complete(
        self,
        exception: Optional[Exception],
        namespace: str,
        project: "Project",
        track: str,
    ) -> Optional[bool]:
        if not self.configured or exception is not None:
            return None

        deployment_message = new_environment_message(track, project)

        try:
            self.client.chat_postMessage(
                channel=self.SLACK_CHANNEL,
                blocks=deployment_message,
                username="******",
                icon_emoji=":rocket:",
            )
        except SlackApiError as e:
            logger.error(
                message=f"Could not send slack message -> {e.response['error']}"
            )

        return True
Beispiel #7
0
def file_shared(body, client: WebClient, context, logger):
    context.ack()
    file_id = body["event"]["file_id"]
    file_info = client.files_info(file=file_id)

    file_type = file_info["file"]["filetype"]
    if file_type not in ["jpg", "jpeg", "png"]:
        return

    url = file_info["file"]["url_private"]

    image = im.open_url(url, cfg.token)

    sides = ["left", "right"]
    uploaded_files = {}
    for side in sides:
        mirrored = im.mirror(image, side=side)
        mirrored.save(f"/tmp/{file_id}-{side}.{file_type}")

        with open(f"/tmp/{file_id}-{side}.{file_type}", "rb") as file_content:
            result = client.files_upload(file=file_content)
            uploaded_files[side] = result["file"]["permalink"]

    msg = f"<{uploaded_files['right']}| ><{uploaded_files['left']}| >"

    channel_name = channel_name_from_id(body["event"]["channel_id"])
    channel = "sapsik"
    if channel_name == "bot_testing":
        channel = channel_name

    sent = client.chat_postMessage(text=msg, channel=channel)
    for side in sides:
        try:
            client.reactions_add(channel=sent["channel"], timestamp=sent["ts"], name=f"point_{side}")
        except SlackApiError:
            pass
Beispiel #8
0
class Slack:
    ''' Client for sending Slack messages '''
    def __init__(self, token: str = None, default_channel: str = None):

        # Rely on system token if one wasn't passed
        if not token:
            token = Slack_Settings.APP_SLACK_TOKEN

        # Create internal client to serve as an adapter for
        self._client = WebClient(token=token)

        # Set the default channel
        self.default_channel = Slack_Settings.APP_SLACK_LOGGING_CHANNEL if not default_channel else default_channel

    def send_message(self,
                     message: str,
                     channel: str = None,
                     thread_id: str = None) -> str:
        ''' Sends a message to the passed Slack channel and returns the thread ID. Posts as a reply if  `thread_id` is passed'''

        # Fall back on the default channel if a channel name isn't immediately passed
        if not channel:
            channel = self.default_channel

        # Ensure the channel name starts with '#'
        if channel[0] != '#':
            channel = f'#{channel}'

        try:
            # Send the message to the channel
            response = self._client.api_call(
                api_method='chat.postMessage',
                json={
                    'channel': channel,
                    'text': message,
                    **({} if not thread_id else {
                           'thread_ts': thread_id
                       })
                },
            )

            # Log errors
            if not response or 'error' in response:
                capture_exception(
                    Exception(f"Slack logging error: {response['error']}"))
                return None

            # Return the thread ID
            return response.get('ts')

        # Catch and log any exceptions thrown when logging
        except Exception as e:
            capture_exception(e)

    def log_api_exception(self,
                          error: API_Error,
                          endpoint: str,
                          payload: dict,
                          channel: str = None,
                          thread_title: str = None):
        ''' Log an API level exception to Slack with supplementary information '''

        # Generate top level message for the error thread if one was not passed
        if not thread_title:
            emoji = ':broken_wifi:' if str(
                error.code)[0] != '4' else ':large_yellow_circle:'
            thread_title = f'{emoji} API Error: `{error.code}`\n:api: Endpoint: `{endpoint}`\n:speech_balloon: Error: `{error.message}`'

        # Post the message and get the ID of the thread
        thread_id = self.send_message(thread_title, channel)

        # Only post replies if the last post succeeded
        if thread_id:

            # Prettify paylod data for Slack
            payload_reply = f':package: Payload:\n```{pformat(payload)}```'

            # Post the payload as a reply
            replied = self.send_message(payload_reply, channel, thread_id)

            # Only post replies if the last post succeeded
            if replied:

                # Prettify traceback data for Slack
                traceback_reply = f':mag: Traceback:\n```{"".join(format_tb(error.__traceback__))}```'

                # Post the traceback as a reply
                self.send_message(traceback_reply, channel, thread_id)

    def log_exception(self,
                      error: Exception,
                      channel: str = None,
                      thread_title: str = None,
                      endpoint: str = None,
                      payload: dict = None):
        ''' Log an exception to Slack with supplementary information '''

        # Generate top level message for the error thread if one was not passed
        if not thread_title:
            thread_title = f':x: Exception: `{error.args[0]}`'

            if endpoint:
                thread_title += f'\n:api: Endpoint: `{endpoint}`'

        # Post the message and get the ID of the thread
        thread_id = self.send_message(thread_title, channel)

        # Only post replies if the last post succeeded
        if thread_id and payload:

            # Prettify paylod data for Slack
            payload_reply = f':package: Payload:\n```{pformat(payload)}```'

            # Post the payload as a reply
            self.send_message(payload_reply, channel, thread_id)

        if thread_id:

            # Prettify traceback data for Slack
            traceback_reply = f':mag: Traceback:\n```{"".join(format_tb(error.__traceback__))}```'

            # Post the traceback as a reply
            self.send_message(traceback_reply, channel, thread_id)
Beispiel #9
0
 def __init__(self, env: Env) -> None:
     self.required_variables = [("SLACK_TOKEN", env.str),
                                ("SLACK_CHANNEL", env.str)]
     self.configure(env)
     self.client = WebClient(self.SLACK_TOKEN)
Beispiel #10
0
class LowLevelSlackClient(metaclass=Singleton):
    def __init__(self):
        _settings, _ = import_settings()
        slack_api_token = _settings.get('SLACK_API_TOKEN', None)
        http_proxy = _settings.get('HTTP_PROXY', None)
        self.rtm_client = RTMClient(token=slack_api_token, proxy=http_proxy)
        self.web_client = WebClient(token=slack_api_token, proxy=http_proxy)
        self._bot_info = {}
        self._users = {}
        self._channels = {}

    @staticmethod
    def get_instance() -> 'LowLevelSlackClient':
        return LowLevelSlackClient()

    def _register_user(self, user_response):
        user = User.from_api_response(user_response)
        self._users[user.id] = user
        return user

    def _register_channel(self, channel_response):
        channel = Channel.from_api_response(channel_response)
        self._channels[channel.id] = channel
        return channel

    def ping(self):
        # Ugly hack because some parts of slackclient > 2.0 are async-only (like the ping function)
        # and Slack Machine isn't async yet
        loop = asyncio.new_event_loop()
        result = self.rtm_client.ping()
        loop.run_until_complete(result)

    def _on_open(self, **payload):
        # Set bot info
        self._bot_info = payload['data']['self']
        # Build user cache
        all_users = call_paginated_endpoint(self.web_client.users_list,
                                            'members')
        for u in all_users:
            self._register_user(u)
        logger.debug("Number of users found: %s" % len(self._users))
        logger.debug("Users: %s" % ", ".join([
            f"{u.profile.display_name}|{u.profile.real_name}"
            for u in self._users.values()
        ]))
        # Build channel cache
        all_channels = call_paginated_endpoint(
            self.web_client.conversations_list,
            'channels',
            types='public_channel,private_channel,mpim,im')
        for c in all_channels:
            self._register_channel(c)
        logger.debug("Number of channels found: %s" % len(self._channels))
        logger.debug("Channels: %s" %
                     ", ".join([c.identifier
                                for c in self._channels.values()]))

        puts("Final initialization of plugins...")
        for instance, class_name in self._plugins:
            instance.init_final()
            show_valid(class_name)

    def _on_team_join(self, **payload):
        user = self._register_user(payload['data']['user'])
        logger.debug("User joined team: %s" % user)

    def _on_user_change(self, **payload):
        user = self._register_user(payload['data']['user'])
        logger.debug("User changed: %s" % user)

    def _on_channel_created(self, **payload):
        channel_resp = self.web_client.conversations_info(
            channel=payload['data']['channel']['id'])
        channel = self._register_channel(channel_resp['channel'])
        logger.debug("Channel created: %s" % channel)

    def _on_channel_updated(self, **payload):
        data = payload['data']
        if isinstance(data['channel'], dict):
            channel_id = data['channel']['id']
        else:
            channel_id = data['channel']
        channel_resp = self.web_client.conversations_info(channel=channel_id)
        channel = self._register_channel(channel_resp['channel'])
        logger.debug("Channel updated: %s" % channel)

    def _on_channel_deleted(self, **payload):
        channel = self._channels[payload['data']['channel']]
        del self._channels[payload['data']['channel']]
        logger.debug("Channel %s deleted" % channel.name)

    @property
    def bot_info(self) -> Dict[str, str]:
        return self._bot_info

    def start(self, plugins):
        self._plugins = plugins
        RTMClient.on(event='open', callback=self._on_open)
        RTMClient.on(event='team_join', callback=self._on_team_join)
        RTMClient.on(event='channel_created',
                     callback=self._on_channel_created)
        RTMClient.on(event='group_joined', callback=self._on_channel_created)
        RTMClient.on(event='mpim_joined', callback=self._on_channel_created)
        RTMClient.on(event='im_created', callback=self._on_channel_created)
        RTMClient.on(event='channel_deleted',
                     callback=self._on_channel_deleted)
        RTMClient.on(event='im_close', callback=self._on_channel_deleted)
        RTMClient.on(event='channel_rename', callback=self._on_channel_updated)
        RTMClient.on(event='channel_archive',
                     callback=self._on_channel_updated)
        RTMClient.on(event='channel_unarchive',
                     callback=self._on_channel_updated)
        RTMClient.on(event='user_change', callback=self._on_user_change)
        self.rtm_client.start()

    @property
    def users(self) -> Dict[str, User]:
        return self._users

    @property
    def channels(self) -> Dict[str, Channel]:
        return self._channels
load_dotenv(find_dotenv())

# Setup the Algolia client
algolia = SearchClient.create(
    app_id=os.getenv('ALGOLIA_APP_ID'),
    api_key=os.getenv('ALGOLIA_API_KEY')
)
employees_index = algolia.init_index(os.getenv('ALGOLIA_INDEX_NAME'))

# Setup the Google Cloud client
# https://cloud.google.com/vision/docs/libraries
gc_vision = vision.ImageAnnotatorClient()

# Setup the Slack client
slack = WebClient(token=os.getenv('SLACK_TOKEN'))

# Setup Flask
STATIC_DIR = str(
    os.path.abspath(os.path.join(
        __file__,
        '..',
        os.getenv('STATIC_DIR')
    ))
)
app = Flask(
    __name__,
    static_folder=STATIC_DIR,
    static_url_path="",
    template_folder=STATIC_DIR
)
Beispiel #12
0
import os
import sys
import json
from datetime import datetime

from slack_sdk.web.client import WebClient

CHANNEL = "#alerts-universe"
SLACK_TOKEN = os.environ.get("SLACK_BOT_TOKEN", "ENV VAR not available!")
DATETIME_FORMAT = "%Y-%m-%dT%H:%M:%SZ"

client = WebClient(SLACK_TOKEN)
github_context = json.loads(sys.argv[1])

event = github_context['event']
pr_title = event['pull_request']["title"]
pr_link = event['pull_request']["patch_url"].replace(".patch", "")
pr_author_url = event['sender']["html_url"]
pr_author_name = pr_author_url.rsplit('/')[-1]
pr_created_at_dt = datetime.strptime(event['pull_request']["created_at"],
                                     DATETIME_FORMAT)
pr_created_at = pr_created_at_dt.strftime("%c")
pr_updated_at_dt = datetime.strptime(event['pull_request']["updated_at"],
                                     DATETIME_FORMAT)
pr_updated_at = pr_updated_at_dt.strftime("%c")

blocks = [{
    "type": "section",
    "text": {
        "type": "mrkdwn",
        "text": "📣 New spaCy Universe Project Alert ✨"