Exemple #1
0
def api_dialogflow_webhook(
    request: HttpRequest,
    user_profile: UserProfile,
    payload: Dict[str, Any] = REQ(argument_type='body'),
    email: str = REQ(default='foo')
) -> HttpResponse:
    status = payload["status"]["code"]

    if status == 200:
        result = payload["result"]["fulfillment"]["speech"]
        if not result:
            alternate_result = payload["alternateResult"]["fulfillment"][
                "speech"]
            if not alternate_result:
                body = u"DialogFlow couldn't process your query."
            else:
                body = alternate_result
        else:
            body = result
    else:
        error_status = payload["status"]["errorDetails"]
        body = u"{} - {}".format(status, error_status)

    profile = get_user_profile_by_email(email)
    check_send_private_message(user_profile, request.client, profile, body)
    return json_success()
Exemple #2
0
def api_beeminder_webhook(request: HttpRequest, user_profile: UserProfile,
                          payload: Dict[str, Any]=REQ(argument_type='body'),
                          stream: Text=REQ(default="beeminder"),
                          email: str=REQ(default='*****@*****.**'),
                          topic: Text=REQ(default='beekeeper')) -> HttpResponse:

    secret = payload["goal"]["secret"]
    goal_name = payload["goal"]["slug"]
    limsum = payload["goal"]["limsum"]
    pledge = payload["goal"]["pledge"]
    time_remain = get_time(payload)  # time in hours
    # To show user's probable reaction by looking at pledge amount
    if pledge > 0:
        expression = ':worried:'
    else:
        expression = ':relieved:'

    if not secret:
        # In this case notifications will be sent to stream
        name = get_user_name(email)
        body = u"Hello **{}**! I am the Beeminder bot! :octopus:\n You are going to derail \
from goal **{}** in **{:0.1f} hours**\n You need **{}** to avoid derailing\n * Pledge: **{}$** {}"
        body = body.format(name, goal_name, time_remain, limsum, pledge, expression)
        check_send_stream_message(user_profile, request.client, stream, topic, body)
        return json_success()

    else:
        # In this case PM will be sent to user
        p = get_user_profile_by_email(email)
        body = u"I am the Beeminder bot! :octopus:\n You are going to derail from \
goal **{}** in **{:0.1f} hours**\n You need **{}** to avoid derailing\n * Pledge: **{}$**{}"
        body = body.format(goal_name, time_remain, limsum, pledge, expression)
        check_send_private_message(user_profile, request.client, p, body)
        return json_success()
Exemple #3
0
def check_send_webhook_message(request: HttpRequest,
                               user_profile: UserProfile,
                               topic: str,
                               body: str,
                               stream: Optional[str] = REQ(default=None),
                               user_specified_topic: Optional[str] = REQ(
                                   "topic", default=None),
                               unquote_stream: Optional[bool] = False) -> None:

    if stream is None:
        assert user_profile.bot_owner is not None
        check_send_private_message(user_profile, request.client,
                                   user_profile.bot_owner, body)
    else:
        # Some third-party websites (such as Atlassian's JIRA), tend to
        # double escape their URLs in a manner that escaped space characters
        # (%20) are never properly decoded. We work around that by making sure
        # that the stream name is decoded on our end.
        if unquote_stream:
            stream = unquote(stream)

        if user_specified_topic is not None:
            topic = user_specified_topic

        try:
            check_send_stream_message(user_profile, request.client, stream,
                                      topic, body)
        except StreamDoesNotExistError:
            # A PM will be sent to the bot_owner by check_message, notifying
            # that the webhook bot just tried to send a message to a non-existent
            # stream, so we don't need to re-raise it since it clutters up
            # webhook-errors.log
            pass
Exemple #4
0
def check_send_webhook_message(
    request: HttpRequest,
    user_profile: UserProfile,
    topic: Text,
    body: Text,
    stream: Optional[Text] = REQ(default=None),
    user_specified_topic: Optional[Text] = REQ("topic", default=None)
) -> None:

    if stream is None:
        assert user_profile.bot_owner is not None
        check_send_private_message(user_profile, request.client,
                                   user_profile.bot_owner, body)
    else:
        if user_specified_topic is not None:
            topic = user_specified_topic

        try:
            check_send_stream_message(user_profile, request.client, stream,
                                      topic, body)
        except StreamDoesNotExistError:
            # A PM will be sent to the bot_owner by check_message, notifying
            # that the webhook bot just tried to send a message to a non-existent
            # stream, so we don't need to re-raise it since it clutters up
            # webhook-errors.log
            pass
Exemple #5
0
def api_dialogflow_webhook(
        request: HttpRequest,
        user_profile: UserProfile,
        payload: Dict[str, Any] = REQ(argument_type="body"),
        email: str = REQ(),
) -> HttpResponse:
    status = payload["status"]["code"]

    if status == 200:
        result = payload["result"]["fulfillment"]["speech"]
        if not result:
            alternate_result = payload["alternateResult"]["fulfillment"][
                "speech"]
            if not alternate_result:
                body = "Dialogflow couldn't process your query."
            else:
                body = alternate_result
        else:
            body = result
    else:
        error_status = payload["status"]["errorDetails"]
        body = f"{status} - {error_status}"

    receiving_user = get_user(email, user_profile.realm)
    check_send_private_message(user_profile, request.client, receiving_user,
                               body)
    return json_success()
Exemple #6
0
def api_yo_app_webhook(request: HttpRequest, user_profile: UserProfile,
                       email: str = REQ(default=""),
                       username: str = REQ(default='Yo Bot'),
                       topic: Optional[str] = REQ(default=None),
                       user_ip: Optional[str] = REQ(default=None)) -> HttpResponse:
    body = ('Yo from %s') % (username,)
    receiving_user = get_user(email, user_profile.realm)
    check_send_private_message(user_profile, request.client, receiving_user, body)
    return json_success()
Exemple #7
0
def api_yo_app_webhook(request: HttpRequest, user_profile: UserProfile,
                       email: str = REQ(default=""),
                       username: str = REQ(default='Yo Bot'),
                       topic: Optional[str] = REQ(default=None),
                       user_ip: Optional[str] = REQ(default=None)) -> HttpResponse:
    body = ('Yo from %s') % (username,)
    receiving_user = get_user(email, user_profile.realm)
    check_send_private_message(user_profile, request.client, receiving_user, body)
    return json_success()
Exemple #8
0
def api_yo_app_webhook(
        request: HttpRequest,
        user_profile: UserProfile,
        email: str = REQ(default=""),
        username: str = REQ(default="Yo Bot"),
        topic: Optional[str] = REQ(default=None),
        user_ip: Optional[str] = REQ(default=None),
) -> HttpResponse:
    body = f"Yo from {username}"
    receiving_user = get_user(email, user_profile.realm)
    client = get_request_notes(request).client
    assert client is not None
    check_send_private_message(user_profile, client, receiving_user, body)
    return json_success()
Exemple #9
0
def check_send_webhook_message(
        request: HttpRequest, user_profile: UserProfile,
        topic: Text, body: Text, stream: Optional[Text]=REQ(default=None),
        user_specified_topic: Optional[Text]=REQ("topic", default=None)
) -> None:

    if stream is None:
        assert user_profile.bot_owner is not None
        check_send_private_message(user_profile, request.client,
                                   user_profile.bot_owner, body)
    else:
        if user_specified_topic is not None:
            topic = user_specified_topic
        check_send_stream_message(user_profile, request.client,
                                  stream, topic, body)
Exemple #10
0
def check_send_webhook_message(
    request: HttpRequest,
    user_profile: UserProfile,
    topic: Text,
    body: Text,
    stream: Optional[Text] = REQ(default=None),
    user_specified_topic: Optional[Text] = REQ("topic", default=None)
) -> None:

    if stream is None:
        assert user_profile.bot_owner is not None
        check_send_private_message(user_profile, request.client,
                                   user_profile.bot_owner, body)
    else:
        if user_specified_topic is not None:
            topic = user_specified_topic
        check_send_stream_message(user_profile, request.client, stream, topic,
                                  body)
Exemple #11
0
def api_dialogflow_webhook(request: HttpRequest, user_profile: UserProfile,
                           payload: Dict[str, Any]=REQ(argument_type='body'),
                           email: str=REQ(default='foo')) -> HttpResponse:
    status = payload["status"]["code"]

    if status == 200:
        result = payload["result"]["fulfillment"]["speech"]
        if not result:
            alternate_result = payload["alternateResult"]["fulfillment"]["speech"]
            if not alternate_result:
                body = u"DialogFlow couldn't process your query."
            else:
                body = alternate_result
        else:
            body = result
    else:
        error_status = payload["status"]["errorDetails"]
        body = u"{} - {}".format(status, error_status)

    profile = get_user_profile_by_email(email)
    check_send_private_message(user_profile, request.client, profile, body)
    return json_success()
Exemple #12
0
def check_send_webhook_message(
        request: HttpRequest, user_profile: UserProfile,
        topic: str, body: str, stream: Optional[str]=REQ(default=None),
        user_specified_topic: Optional[str]=REQ("topic", default=None)
) -> None:

    if stream is None:
        assert user_profile.bot_owner is not None
        check_send_private_message(user_profile, request.client,
                                   user_profile.bot_owner, body)
    else:
        if user_specified_topic is not None:
            topic = user_specified_topic

        try:
            check_send_stream_message(user_profile, request.client,
                                      stream, topic, body)
        except StreamDoesNotExistError:
            # A PM will be sent to the bot_owner by check_message, notifying
            # that the webhook bot just tried to send a message to a non-existent
            # stream, so we don't need to re-raise it since it clutters up
            # webhook-errors.log
            pass
Exemple #13
0
def api_beeminder_webhook(request: HttpRequest, user_profile: UserProfile,
                          payload: Dict[str, Any]=REQ(argument_type='body'),
                          stream: Text=REQ(default="beeminder"),
                          email: str=REQ(default='*****@*****.**'),
                          topic: Text=REQ(default='beekeeper')) -> HttpResponse:

    secret = payload["goal"]["secret"]
    goal_name = payload["goal"]["slug"]
    losedate = payload["goal"]["losedate"]
    limsum = payload["goal"]["limsum"]
    pledge = payload["goal"]["pledge"]
    time_remain = (losedate - current_time)/3600   # time in hours
    # To show user's probable reaction by looking at pledge amount
    if pledge > 0:
        expression = ':worried:'
    else:
        expression = ':relieved:'

    if not secret:
        # In this case notifications will be sent to stream

        name = get_user_name(email)
        body = u"Hello **{}**! I am the Beeminder bot! :octopus: \n You are going to derail \
        from goal **{}** in **{:0.1f} hours** \n You need **{}** to avoid derailing \n * Pledge: **{}$** {}"
        body = body.format(name, goal_name, time_remain, limsum, pledge, expression)
        check_send_stream_message(user_profile, request.client, stream, topic, body)
        return json_success()

    else:
        # In this case PM will be sent to user
        p = get_user_profile_by_email(email)
        body = u"I am the Beeminder bot! :octopus: \n You are going to derail from \
        goal **{}** in **{:0.1f} hours** \n You need **{}** to avoid derailing \n * Pledge: **{}$**{}"
        body = body.format(goal_name, time_remain, limsum, pledge, expression)
        check_send_private_message(user_profile, request.client, p, body)
        return json_success()
Exemple #14
0
def api_teamcity_webhook(request: HttpRequest, user_profile: UserProfile,
                         payload: Dict[str, Any]=REQ(argument_type='body')) -> HttpResponse:
    message = payload.get('build')
    if message is None:
        # Ignore third-party specific (e.g. Slack/HipChat) payload formats
        # and notify the bot owner
        message = MISCONFIGURED_PAYLOAD_TYPE_ERROR_MESSAGE.format(
            bot_name=user_profile.full_name,
            support_email=FromAddress.SUPPORT,
        ).strip()
        send_rate_limited_pm_notification_to_bot_owner(
            user_profile, user_profile.realm, message)

        return json_success()

    build_name = message['buildFullName']
    build_url = message['buildStatusUrl']
    changes_url = build_url + '&tab=buildChangesDiv'
    build_number = message['buildNumber']
    build_result = message['buildResult']
    build_result_delta = message['buildResultDelta']
    build_status = message['buildStatus']

    if build_result == 'success':
        if build_result_delta == 'fixed':
            status = 'has been fixed! :thumbs_up:'
        else:
            status = 'was successful! :thumbs_up:'
    elif build_result == 'failure':
        if build_result_delta == 'broken':
            status = 'is broken with status %s! :thumbs_down:' % (build_status,)
        else:
            status = 'is still broken with status %s! :thumbs_down:' % (build_status,)
    elif build_result == 'running':
        status = 'has started.'
    else:
        status = '(has no message specified for status %s)' % (build_status,)

    template = (
        u'%s build %s %s\n'
        u'Details: [changes](%s), [build log](%s)')

    body = template % (build_name, build_number, status, changes_url, build_url)

    if 'branchDisplayName' in message:
        topic = build_name + ' (' + message['branchDisplayName'] + ')'
    else:
        topic = build_name

    # Check if this is a personal build, and if so try to private message the user who triggered it.
    if get_teamcity_property_value(message['teamcityProperties'], 'env.BUILD_IS_PERSONAL') == 'true':
        # The triggeredBy field gives us the teamcity user full name, and the
        # "teamcity.build.triggeredBy.username" property gives us the teamcity username.
        # Let's try finding the user email from both.
        teamcity_fullname = message['triggeredBy'].split(';')[0]
        teamcity_user = guess_zulip_user_from_teamcity(teamcity_fullname, user_profile.realm)

        if teamcity_user is None:
            teamcity_shortname = get_teamcity_property_value(message['teamcityProperties'],
                                                             'teamcity.build.triggeredBy.username')
            if teamcity_shortname is not None:
                teamcity_user = guess_zulip_user_from_teamcity(teamcity_shortname, user_profile.realm)

        if teamcity_user is None:
            # We can't figure out who started this build - there's nothing we can do here.
            logging.info("Teamcity webhook couldn't find a matching Zulip user for "
                         "Teamcity user '%s' or '%s'" % (teamcity_fullname, teamcity_shortname))
            return json_success()

        body = "Your personal build of " + body
        check_send_private_message(user_profile, request.client, teamcity_user, body)

        return json_success()

    check_send_webhook_message(request, user_profile, topic, body)
    return json_success()
Exemple #15
0
def api_teamcity_webhook(
        request: HttpRequest,
        user_profile: UserProfile,
        payload: Dict[str, Any] = REQ(argument_type="body"),
) -> HttpResponse:
    message = payload.get("build")
    if message is None:
        # Ignore third-party specific (e.g. Slack) payload formats
        # and notify the bot owner
        message = MISCONFIGURED_PAYLOAD_TYPE_ERROR_MESSAGE.format(
            bot_name=user_profile.full_name,
            support_email=FromAddress.SUPPORT,
        ).strip()
        send_rate_limited_pm_notification_to_bot_owner(user_profile,
                                                       user_profile.realm,
                                                       message)

        return json_success()

    build_name = message["buildFullName"]
    build_url = message["buildStatusUrl"]
    changes_url = build_url + "&tab=buildChangesDiv"
    build_number = message["buildNumber"]
    build_result = message["buildResult"]
    build_result_delta = message["buildResultDelta"]
    build_status = message["buildStatus"]

    if build_result == "success":
        if build_result_delta == "fixed":
            status = "has been fixed! :thumbs_up:"
        else:
            status = "was successful! :thumbs_up:"
    elif build_result == "failure":
        if build_result_delta == "broken":
            status = f"is broken with status {build_status}! :thumbs_down:"
        else:
            status = f"is still broken with status {build_status}! :thumbs_down:"
    elif build_result == "running":
        status = "has started."

    template = """
{build_name} build {build_id} {status} See [changes]\
({changes_url}) and [build log]({log_url}).
""".strip()

    body = template.format(
        build_name=build_name,
        build_id=build_number,
        status=status,
        changes_url=changes_url,
        log_url=build_url,
    )

    if "branchDisplayName" in message:
        topic = "{} ({})".format(build_name, message["branchDisplayName"])
    else:
        topic = build_name

    # Check if this is a personal build, and if so try to private message the user who triggered it.
    if (get_teamcity_property_value(message["teamcityProperties"],
                                    "env.BUILD_IS_PERSONAL") == "true"):
        # The triggeredBy field gives us the teamcity user full name, and the
        # "teamcity.build.triggeredBy.username" property gives us the teamcity username.
        # Let's try finding the user email from both.
        teamcity_fullname = message["triggeredBy"].split(";")[0]
        teamcity_user = guess_zulip_user_from_teamcity(teamcity_fullname,
                                                       user_profile.realm)

        if teamcity_user is None:
            teamcity_shortname = get_teamcity_property_value(
                message["teamcityProperties"],
                "teamcity.build.triggeredBy.username")
            if teamcity_shortname is not None:
                teamcity_user = guess_zulip_user_from_teamcity(
                    teamcity_shortname, user_profile.realm)

        if teamcity_user is None:
            # We can't figure out who started this build - there's nothing we can do here.
            logging.info(
                "Teamcity webhook couldn't find a matching Zulip user for "
                "Teamcity user '%s' or '%s'",
                teamcity_fullname,
                teamcity_shortname,
            )
            return json_success()

        body = f"Your personal build for {body}"
        client = get_request_notes(request).client
        assert client is not None
        check_send_private_message(user_profile, client, teamcity_user, body)

        return json_success()

    check_send_webhook_message(request, user_profile, topic, body)
    return json_success()
Exemple #16
0
def check_send_webhook_message(
    request: HttpRequest,
    user_profile: UserProfile,
    topic: str,
    body: str,
    complete_event_type: Optional[str] = None,
    stream: Optional[str] = REQ(default=None),
    user_specified_topic: Optional[str] = REQ("topic", default=None),
    only_events: Optional[List[str]] = REQ(
        default=None, json_validator=check_list(check_string)),
    exclude_events: Optional[List[str]] = REQ(
        default=None, json_validator=check_list(check_string)),
    unquote_url_parameters: bool = False,
) -> None:
    if complete_event_type is not None:
        # Here, we implement Zulip's generic support for filtering
        # events sent by the third-party service.
        #
        # If complete_event_type is passed to this function, we will check the event
        # type against user configured lists of only_events and exclude events.
        # If the event does not satisfy the configuration, the function will return
        # without sending any messages.
        #
        # We match items in only_events and exclude_events using Unix
        # shell-style wildcards.
        if (only_events is not None and all([
                not fnmatch.fnmatch(complete_event_type, pattern)
                for pattern in only_events
        ])) or (exclude_events is not None and any([
                fnmatch.fnmatch(complete_event_type, pattern)
                for pattern in exclude_events
        ])):
            return

    client = get_request_notes(request).client
    assert client is not None
    if stream is None:
        assert user_profile.bot_owner is not None
        check_send_private_message(user_profile, client,
                                   user_profile.bot_owner, body)
    else:
        # Some third-party websites (such as Atlassian's Jira), tend to
        # double escape their URLs in a manner that escaped space characters
        # (%20) are never properly decoded. We work around that by making sure
        # that the URL parameters are decoded on our end.
        if stream is not None and unquote_url_parameters:
            stream = unquote(stream)

        if user_specified_topic is not None:
            topic = user_specified_topic
            if unquote_url_parameters:
                topic = unquote(topic)

        try:
            if stream.isdecimal():
                check_send_stream_message_by_id(user_profile, client,
                                                int(stream), topic, body)
            else:
                check_send_stream_message(user_profile, client, stream, topic,
                                          body)
        except StreamDoesNotExistError:
            # A PM will be sent to the bot_owner by check_message, notifying
            # that the webhook bot just tried to send a message to a non-existent
            # stream, so we don't need to re-raise it since it clutters up
            # webhook-errors.log
            pass
Exemple #17
0
def api_teamcity_webhook(request: HttpRequest, user_profile: UserProfile,
                         payload: Dict[str, Any]=REQ(argument_type='body'),
                         stream: str=REQ(default='teamcity')) -> HttpResponse:
    message = payload['build']

    build_name = message['buildFullName']
    build_url = message['buildStatusUrl']
    changes_url = build_url + '&tab=buildChangesDiv'
    build_number = message['buildNumber']
    build_result = message['buildResult']
    build_result_delta = message['buildResultDelta']
    build_status = message['buildStatus']

    if build_result == 'success':
        if build_result_delta == 'fixed':
            status = 'has been fixed! :thumbs_up:'
        else:
            status = 'was successful! :thumbs_up:'
    elif build_result == 'failure':
        if build_result_delta == 'broken':
            status = 'is broken with status %s! :thumbs_down:' % (build_status,)
        else:
            status = 'is still broken with status %s! :thumbs_down:' % (build_status,)
    elif build_result == 'running':
        status = 'has started.'
    else:
        status = '(has no message specified for status %s)' % (build_status,)

    template = (
        u'%s build %s %s\n'
        u'Details: [changes](%s), [build log](%s)')

    body = template % (build_name, build_number, status, changes_url, build_url)
    topic = build_name

    # Check if this is a personal build, and if so try to private message the user who triggered it.
    if get_teamcity_property_value(message['teamcityProperties'], 'env.BUILD_IS_PERSONAL') == 'true':
        # The triggeredBy field gives us the teamcity user full name, and the
        # "teamcity.build.triggeredBy.username" property gives us the teamcity username.
        # Let's try finding the user email from both.
        teamcity_fullname = message['triggeredBy'].split(';')[0]
        teamcity_user = guess_zulip_user_from_teamcity(teamcity_fullname, user_profile.realm)

        if teamcity_user is None:
            teamcity_shortname = get_teamcity_property_value(message['teamcityProperties'],
                                                             'teamcity.build.triggeredBy.username')
            if teamcity_shortname is not None:
                teamcity_user = guess_zulip_user_from_teamcity(teamcity_shortname, user_profile.realm)

        if teamcity_user is None:
            # We can't figure out who started this build - there's nothing we can do here.
            logging.info("Teamcity webhook couldn't find a matching Zulip user for "
                         "Teamcity user '%s' or '%s'" % (teamcity_fullname, teamcity_shortname))
            return json_success()

        body = "Your personal build of " + body
        check_send_private_message(user_profile, request.client, teamcity_user, body)

        return json_success()

    check_send_stream_message(user_profile, request.client, stream, topic, body)
    return json_success()
Exemple #18
0
def api_teamcity_webhook(request: HttpRequest, user_profile: UserProfile,
                         payload: Dict[str, Any]=REQ(argument_type='body'),
                         stream: str=REQ(default='teamcity')) -> HttpResponse:
    message = payload['build']

    build_name = message['buildFullName']
    build_url = message['buildStatusUrl']
    changes_url = build_url + '&tab=buildChangesDiv'
    build_number = message['buildNumber']
    build_result = message['buildResult']
    build_result_delta = message['buildResultDelta']
    build_status = message['buildStatus']

    if build_result == 'success':
        if build_result_delta == 'fixed':
            status = 'has been fixed! :thumbsup:'
        else:
            status = 'was successful! :thumbsup:'
    elif build_result == 'failure':
        if build_result_delta == 'broken':
            status = 'is broken with status %s! :thumbsdown:' % (build_status,)
        else:
            status = 'is still broken with status %s! :thumbsdown:' % (build_status,)
    elif build_result == 'running':
        status = 'has started.'
    else:
        status = '(has no message specified for status %s)' % (build_status,)

    template = (
        u'%s build %s %s\n'
        u'Details: [changes](%s), [build log](%s)')

    body = template % (build_name, build_number, status, changes_url, build_url)
    topic = build_name

    # Check if this is a personal build, and if so try to private message the user who triggered it.
    if get_teamcity_property_value(message['teamcityProperties'], 'env.BUILD_IS_PERSONAL') == 'true':
        # The triggeredBy field gives us the teamcity user full name, and the
        # "teamcity.build.triggeredBy.username" property gives us the teamcity username.
        # Let's try finding the user email from both.
        teamcity_fullname = message['triggeredBy'].split(';')[0]
        teamcity_user = guess_zulip_user_from_teamcity(teamcity_fullname, user_profile.realm)

        if teamcity_user is None:
            teamcity_shortname = get_teamcity_property_value(message['teamcityProperties'],
                                                             'teamcity.build.triggeredBy.username')
            if teamcity_shortname is not None:
                teamcity_user = guess_zulip_user_from_teamcity(teamcity_shortname, user_profile.realm)

        if teamcity_user is None:
            # We can't figure out who started this build - there's nothing we can do here.
            logging.info("Teamcity webhook couldn't find a matching Zulip user for "
                         "Teamcity user '%s' or '%s'" % (teamcity_fullname, teamcity_shortname))
            return json_success()

        body = "Your personal build of " + body
        check_send_private_message(user_profile, request.client, teamcity_user, body)

        return json_success()

    check_send_stream_message(user_profile, request.client, stream, topic, body)
    return json_success()