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()
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()
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
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
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()
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()
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()
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)
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)
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()
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
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()
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()
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()
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
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()
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()