示例#1
0
def dadjoke_cmd(channel: str, message: str, use_api: bool = True) -> None:
    """Send the pinged user a dad joke. Or just send everybody a joke."""
    parsed_message = message.split()
    ping_username, msg = None, None
    try:
        if use_api:
            joke = requests.get("https://icanhazdadjoke.com/",
                                headers={
                                    "Accept": "text/plain"
                                }).content.decode()
        else:
            raise Exception("Testing mode -- just use fallback.")
    except:  # noqa: E722
        joke = i18n["slack"]["dadjoke"]["fallback_joke"]

    if len(parsed_message) == 2:
        if parsed_message[1].startswith("<"):
            ping_username = parsed_message[1].upper()

        if ping_username:
            msg = i18n["slack"]["dadjoke"]["message"].format(
                ping_username, joke)

    if not msg:
        msg = joke

    client.chat_postMessage(channel=channel, text=msg, link_names=True)
示例#2
0
def process_action(data: Dict) -> None:
    """Process a Slack action, e.g. a button press."""
    value = data["actions"][0].get("value")
    if "approve" in value or "remove" in value:
        process_submission_report_update(data)
    else:
        client.chat_postMessage(
            channel=data["channel"]["id"],
            text=i18n["slack"]["errors"]["unknown_payload"].format(value),
        )
示例#3
0
def info_cmd(channel: str, message: str) -> None:
    """Send info about a user to slack."""
    parsed_message = message.split()
    if len(parsed_message) == 1:
        # they just sent an empty info message, create a summary response
        data = Summary().generate_summary()
        client.chat_postMessage(
            channel=channel,
            text=i18n["slack"]["server_summary"].format("\n".join(
                dict_to_table(data))),
        )
        return

    elif len(parsed_message) == 2:
        if user := BlossomUser.objects.filter(
                username__iexact=parsed_message[1]).first():
            v_data = VolunteerSerializer(user).data
            msg = i18n["slack"]["user_info"].format(
                user.username, "\n".join(dict_to_table(v_data)))
        else:
            msg = i18n["slack"]["errors"]["no_user_by_that_name"]
示例#4
0
def _check_for_rank_up(user: BlossomUser, submission: Submission = None) -> None:
    """
    Check if a volunteer has changed rank and, if so, notify Slack.

    Because gamma is calculated off of transcriptions and the `done` endpoint
    is called after the transcription is posted, by the time that we go to
    calculate the gamma of the user, their gamma has already changed... so
    we'll just subtract one from their current score and see if that changes
    anything.
    """
    current_rank = user.get_rank()
    if user.get_rank(override=user.gamma - 1) != current_rank:
        msg = (
            f"Congrats to {user.username} on achieving the rank of {current_rank}!!"
            f" {submission.tor_url}"
        )
        try:
            slack.chat_postMessage(channel=settings.SLACK_RANK_UP_CHANNEL, text=msg)
        except:  # noqa
            logger.warning(f"Cannot post message to slack. Msg: {msg}")
            pass
示例#5
0
def watch_cmd(channel: str, message: str) -> None:
    """Overwrite the transcription check percentage of a user."""
    parsed_message = message.split()

    if len(parsed_message) == 1:
        # they didn't give a username
        msg = i18n["slack"]["errors"]["missing_username"]
    elif len(parsed_message) <= 3:
        username = clean_links(parsed_message[1])
        if user := BlossomUser.objects.filter(
                username__iexact=username).first():
            if len(parsed_message) == 2:
                # they didn't give a percentage, default to 100%
                decimal_percentage = 1
            else:
                # parse the provided percentage
                percentage = parsed_message[2]

                try:
                    # Try to parse the new check percentage
                    percentage = int(percentage.rstrip(" %"))
                    if percentage < 0 or percentage > 100:
                        raise ValueError

                    decimal_percentage = percentage / 100
                except ValueError:
                    # The percentage is invalid
                    msg = i18n["slack"]["watch"]["invalid_percentage"].format(
                        percentage=percentage)
                    client.chat_postMessage(channel=channel, text=msg)
                    return

            # Overwrite the check percentage
            user.overwrite_check_percentage = decimal_percentage
            user.save()

            msg = i18n["slack"]["watch"]["success"].format(
                user=user.username, percentage=decimal_percentage)
        else:
            msg = i18n["slack"]["errors"]["unknown_username"]
示例#6
0
def _worker() -> None:
    """Create worker for background tasks."""
    while True:
        func, args, kwargs = _queue.get()
        try:
            func(*args, **kwargs)
        except:  # noqa: E722
            import traceback

            # prevent circular dependency
            from api.slack import client

            details = traceback.format_exc()
            message = f"Background worker exception: ```{details}```"
            if settings.ENABLE_SLACK:
                client.chat_postMessage(
                    channel=settings.SLACK_DEFAULT_CHANNEL,
                    text=message,
                )
            log.error(message)
        finally:
            _queue.task_done()  # so we can join at exit
示例#7
0
def send_github_sponsors_message(data: Dict, action: str) -> None:
    """
    Process the POST request from GitHub Sponsors.

    Every time someone performs an action on GitHub Sponsors, we'll get
    a POST request with the intent and some other information. This translates
    the GitHub call to something that Slack can understand, then forwards it
    to the #org_running channel.
    """
    emote = ":tada:"
    if action == "cancelled" or action == "pending_cancellation":
        emote = ":sob:"
    if (action == "edited" or action == "tier_changed"
            or action == "pending_tier_change"):
        emote = ":rotating_light:"
    username = data["sponsorship"]["sponsor"]["login"]
    sponsorlevel = data["sponsorship"]["tier"]["name"]

    msg = i18n["slack"]["github_sponsor_update"].format(
        emote, action, username, sponsorlevel)
    client.chat_postMessage(channel=settings.SLACK_GITHUB_SPONSORS_CHANNEL,
                            text=msg)
示例#8
0
def watchlist_cmd(channel: str, message: str) -> None:
    """Send a list of users who are currently being watched."""
    parsed_message = message.split()
    sorting = parsed_message[1] if len(parsed_message) > 1 else "percentage"

    response_msg = "**List of all watched users:**\n\n"

    watched_users: List[BlossomUser] = list(
        BlossomUser.objects.filter(overwrite_check_percentage__isnull=False))

    if len(watched_users) == 0:
        # No users are watched yet
        response_msg += (
            "None yet. Use `@Blossom watch <username> <percentage>` to watch a user."
        )

        client.chat_postMessage(channel=channel, text=response_msg)
        return
    else:
        response_msg += "```\n"

    if sorting == "percentage":
        # Group the users by percentages
        watched_users.sort(key=lambda u: u.overwrite_check_percentage,
                           reverse=True)
        last_percentage = None

        for usr in watched_users:
            if usr.overwrite_check_percentage == last_percentage:
                response_msg += " " * 6 + f"u/{usr.username}\n"
            else:
                response_msg += "{}: u/{}\n".format(
                    f"{usr.overwrite_check_percentage:.0%}".rjust(4, " "),
                    usr.username)
                last_percentage = usr.overwrite_check_percentage
    elif sorting == "alphabetical":
        # Sort the users alphabetically
        watched_users.sort(key=lambda u: u.username.casefold())

        for usr in watched_users:
            response_msg += "u/{} ({:.0%})\n".format(
                usr.username, usr.overwrite_check_percentage)
    else:
        # Invalid sorting
        response_msg = (f"Invalid sorting '{sorting}'. "
                        "Use either 'percentage' or 'alphabetical'.")
        client.chat_postMessage(channel=channel, text=response_msg)
        return

    response_msg += "```"
    client.chat_postMessage(channel=channel, text=response_msg.strip())
示例#9
0
def process_command(data: Dict) -> None:
    """Process a Slack command."""
    e = data.get("event")  # noqa: VNE001
    channel = e.get("channel")

    message = get_message(data)
    actions = data.get("actions")

    if not message and not actions:
        client.chat_postMessage(
            channel=channel,
            text=i18n["slack"]["errors"]["message_parse_error"],
        )
        return

    if not message:
        client.chat_postMessage(
            channel=channel,
            text=i18n["slack"]["errors"]["empty_message_error"],
        )
        return

    # format: first word command -> function to call
    # Reformatted this way because E228 hates the if / elif routing tree.
    options = {
        "ping": pong_cmd,
        "help": help_cmd,
        "reset": reset_cmd,
        "info": info_cmd,
        "blacklist": blacklist_cmd,
        "watch": watch_cmd,
        "unwatch": unwatch_cmd,
        "watchlist": watchlist_cmd,
        "dadjoke": dadjoke_cmd,
    }

    tokens = message.split()

    if len(tokens) > 0:
        # Find the command corresponding to the message
        cmd_name = tokens[0].casefold()
        for key in options.keys():
            if cmd_name == key:
                options[key](channel, message)
                return

    # if we fall through here, we got a message that we don't understand.
    client.chat_postMessage(channel=channel,
                            text=i18n["slack"]["errors"]["unknown_request"])
示例#10
0
def ask_about_removing_post(submission: Submission, reason: str) -> None:
    """Ask Slack if we want to remove a reported submission or not."""
    # Check if this got already sent to mod chat, we don't want duplicates
    if (submission.report_slack_channel_id is not None
            or submission.report_slack_message_ts is not None):
        return

    submission.report_reason = reason
    submission.save(skip_extras=True)

    response = client.chat_postMessage(
        channel=settings.SLACK_REPORTED_POST_CHANNEL,
        blocks=_construct_report_message_blocks(submission,
                                                ReportMessageStatus.REPORTED),
    )
    if not response["ok"]:
        logger.warning(
            f"Could not send report for submission {submission.id} to Slack!")
        return

    # See https://api.slack.com/methods/chat.postMessage
    submission.report_slack_channel_id = response["channel"]
    submission.report_slack_message_ts = response["message"]["ts"]
    submission.save()
示例#11
0
def help_cmd(channel: str, _message: str) -> None:
    """Post a help message to slack."""
    client.chat_postMessage(channel=channel,
                            text=i18n["slack"]["help_message"])
示例#12
0
def pong_cmd(channel: str, _message: str) -> None:
    """Respond to pings."""
    client.chat_postMessage(channel=channel, text="PONG")
示例#13
0
                dict_to_table(data))),
        )
        return

    elif len(parsed_message) == 2:
        if user := BlossomUser.objects.filter(
                username__iexact=parsed_message[1]).first():
            v_data = VolunteerSerializer(user).data
            msg = i18n["slack"]["user_info"].format(
                user.username, "\n".join(dict_to_table(v_data)))
        else:
            msg = i18n["slack"]["errors"]["no_user_by_that_name"]
    else:
        msg = i18n["slack"]["errors"]["too_many_params"]

    client.chat_postMessage(channel=channel, text=msg)


def pong_cmd(channel: str, _message: str) -> None:
    """Respond to pings."""
    client.chat_postMessage(channel=channel, text="PONG")


def reset_cmd(channel: str, message: str) -> None:
    """Reset the CoC status for a given volunteer."""
    parsed_message = message.split()
    if len(parsed_message) == 1:
        # they didn't give a username
        msg = i18n["slack"]["errors"]["missing_username"]
    elif len(parsed_message) == 2:
        username = clean_links(parsed_message[1])