Esempio n. 1
0
def get_channel_id_with_timeout(integration, name, timeout):
    """
    Fetches the internal slack id of a channel.
    :param integration: The slack integration
    :param name: The name of the channel
    :param timeout: Our self-imposed time limit.
    :return: a tuple of three values
        1. prefix: string (`"#"` or `"@"`)
        2. channel_id: string or `None`
        3. timed_out: boolean (whether we hit our self-imposed time limit)
    """

    token_payload = {"token": integration.metadata["access_token"]}

    # Look for channel ID
    payload = dict(token_payload, **{
        "exclude_archived": False,
        "exclude_members": True
    })

    # workspace tokens are the only tokens that don't works with the conversations.list endpoint,
    # once eveyone is migrated we can remove this check and usages of channels.list
    if get_integration_type(integration) == "workspace_app":
        list_types = LEGACY_LIST_TYPES
    else:
        list_types = LIST_TYPES
        payload = dict(payload, **{"types": "public_channel,private_channel"})

    time_to_quit = time.time() + timeout

    client = SlackClient()
    id_data = None
    found_duplicate = False
    for list_type, result_name, prefix in list_types:
        cursor = ""
        while True:
            endpoint = "/%s.list" % list_type
            try:
                # Slack limits the response of `<list_type>.list` to 1000 channels
                items = client.get(endpoint,
                                   params=dict(payload,
                                               cursor=cursor,
                                               limit=1000))
            except ApiError as e:
                logger.info("rule.slack.%s_list_failed" % list_type,
                            extra={"error": six.text_type(e)})
                return (prefix, None, False)

            for c in items[result_name]:
                # The "name" field is unique (this is the username for users)
                # so we return immediately if we find a match.
                # convert to lower case since all names in Slack are lowercase
                if c["name"].lower() == name.lower():
                    return (prefix, c["id"], False)
                # If we don't get a match on a unique identifier, we look through
                # the users' display names, and error if there is a repeat.
                if list_type == "users":
                    profile = c.get("profile")
                    if profile and profile.get("display_name") == name:
                        if id_data:
                            found_duplicate = True
                        else:
                            id_data = (prefix, c["id"], False)

            cursor = items.get("response_metadata",
                               {}).get("next_cursor", None)
            if time.time() > time_to_quit:
                return (prefix, None, True)

            if not cursor:
                break
        if found_duplicate:
            raise DuplicateDisplayNameError(name)
        elif id_data:
            return id_data

    return (prefix, None, False)
Esempio n. 2
0
def get_channel_id_with_timeout(
    integration: Integration,
    name: Optional[str],
    timeout: int,
) -> Tuple[str, Optional[str], bool]:
    """
    Fetches the internal slack id of a channel.
    :param integration: The slack integration
    :param name: The name of the channel
    :param timeout: Our self-imposed time limit.
    :return: a tuple of three values
        1. prefix: string (`"#"` or `"@"`)
        2. channel_id: string or `None`
        3. timed_out: boolean (whether we hit our self-imposed time limit)
    """

    headers = {"Authorization": f"Bearer {integration.metadata['access_token']}"}

    payload = {
        "exclude_archived": False,
        "exclude_members": True,
        "types": "public_channel,private_channel",
    }

    list_types = LIST_TYPES

    time_to_quit = time.time() + timeout

    client = SlackClient()
    id_data: Optional[Tuple[str, Optional[str], bool]] = None
    found_duplicate = False
    prefix = ""
    for list_type, result_name, prefix in list_types:
        cursor = ""
        while True:
            endpoint = f"/{list_type}.list"
            try:
                # Slack limits the response of `<list_type>.list` to 1000 channels
                items = client.get(
                    endpoint, headers=headers, params=dict(payload, cursor=cursor, limit=1000)
                )
            except ApiRateLimitedError as e:
                logger.info(f"rule.slack.{list_type}_list_rate_limited", extra={"error": str(e)})
                raise e
            except ApiError as e:
                logger.info(f"rule.slack.{list_type}_list_rate_limited", extra={"error": str(e)})
                return (prefix, None, False)

            if not isinstance(items, dict):
                continue

            for c in items[result_name]:
                # The "name" field is unique (this is the username for users)
                # so we return immediately if we find a match.
                # convert to lower case since all names in Slack are lowercase
                if name and c["name"].lower() == name.lower():
                    return (prefix, c["id"], False)
                # If we don't get a match on a unique identifier, we look through
                # the users' display names, and error if there is a repeat.
                if list_type == "users":
                    profile = c.get("profile")
                    if profile and profile.get("display_name") == name:
                        if id_data:
                            found_duplicate = True
                        else:
                            id_data = (prefix, c["id"], False)

            cursor = items.get("response_metadata", {}).get("next_cursor", None)
            if time.time() > time_to_quit:
                return (prefix, None, True)

            if not cursor:
                break
        if found_duplicate:
            raise DuplicateDisplayNameError(name)
        elif id_data:
            return id_data

    return (prefix, None, False)