Don't handle json payload key errors inside webhooks.

Fixes first part of #6213.
This commit is contained in:
Robert Hönig
2017-08-24 17:31:04 +02:00
committed by Tim Abbott
parent ecb428100f
commit 18a080cd6c
23 changed files with 273 additions and 363 deletions

View File

@@ -78,24 +78,19 @@ def api_helloworld_webhook(request, user_profile,
topic=REQ(default='Hello World')): topic=REQ(default='Hello World')):
# type: (HttpRequest, UserProfile, Dict[str, Iterable[Dict[str, Any]]], Text, Optional[Text]) -> HttpResponse # type: (HttpRequest, UserProfile, Dict[str, Iterable[Dict[str, Any]]], Text, Optional[Text]) -> HttpResponse
# construct the body of the message # construct the body of the message
body = 'Hello! I am happy to be here! :smile:' body = 'Hello! I am happy to be here! :smile:'
# try to add the Wikipedia article of the day # try to add the Wikipedia article of the day
# return appropriate error if not successful body_template = '\nThe Wikipedia featured article for today is **[{featured_title}]({featured_url})**'
try: body += body_template.format(**payload)
body_template = '\nThe Wikipedia featured article for today is **[{featured_title}]({featured_url})**'
body += body_template.format(**payload)
except KeyError as e:
return json_error(_("Missing key {} in JSON").format(str(e)))
# send the message # send the message
check_send_message(user_profile, request.client, 'stream', check_send_message(user_profile, request.client, 'stream',
[stream], topic, body) [stream], topic, body)
# return json result
return json_success()
# return json result
return json_success()
``` ```
The above code imports the required functions and defines the main webhook The above code imports the required functions and defines the main webhook
@@ -137,10 +132,11 @@ functions.
In the body of the function we define the body of the message as `Hello! I am In the body of the function we define the body of the message as `Hello! I am
happy to be here! :smile:`. The `:smile:` indicates an emoji. Then we append a happy to be here! :smile:`. The `:smile:` indicates an emoji. Then we append a
link to the Wikipedia article of the day as provided by the json payload. If link to the Wikipedia article of the day as provided by the json payload.
the json payload does not include data for `featured_title` and `featured_url`
we catch a `KeyError` and use `json_error` to return the appropriate * Sometimes, it might occur that a json payload does not contain all required keys your
information: a 400 http status code with relevant details. integration checks for. In such a case, any `KeyError` thrown is handled by the server
backend and will create an appropriate response.
Then we send a public (stream) message with `check_send_message` which will Then we send a public (stream) message with `check_send_message` which will
validate the message and then send it. validate the message and then send it.

View File

@@ -17,12 +17,8 @@ def api_airbrake_webhook(request, user_profile,
payload=REQ(argument_type='body'), payload=REQ(argument_type='body'),
stream=REQ(default='airbrake')): stream=REQ(default='airbrake')):
# type: (HttpRequest, UserProfile, Dict[str, Any], Text) -> HttpResponse # type: (HttpRequest, UserProfile, Dict[str, Any], Text) -> HttpResponse
try: subject = get_subject(payload)
subject = get_subject(payload) body = get_body(payload)
body = get_body(payload)
except KeyError as e:
return json_error(_("Missing key {} in JSON").format(str(e)))
check_send_message(user_profile, request.client, 'stream', [stream], subject, body) check_send_message(user_profile, request.client, 'stream', [stream], subject, body)
return json_success() return json_success()

View File

@@ -17,10 +17,7 @@ from typing import Dict, Any, Text
def api_appfollow_webhook(request, user_profile, stream=REQ(default="appfollow"), def api_appfollow_webhook(request, user_profile, stream=REQ(default="appfollow"),
payload=REQ(argument_type="body")): payload=REQ(argument_type="body")):
# type: (HttpRequest, UserProfile, Text, Dict[str, Any]) -> HttpResponse # type: (HttpRequest, UserProfile, Text, Dict[str, Any]) -> HttpResponse
try: message = payload["text"]
message = payload["text"]
except KeyError:
return json_error(_("Missing 'text' argument in JSON"))
app_name = re.search('\A(.+)', message).group(0) app_name = re.search('\A(.+)', message).group(0)
check_send_message(user_profile, request.client, "stream", [stream], app_name, convert_markdown(message)) check_send_message(user_profile, request.client, "stream", [stream], app_name, convert_markdown(message))

View File

@@ -44,25 +44,20 @@ class UnknownTriggerType(Exception):
def api_bitbucket2_webhook(request, user_profile, payload=REQ(argument_type='body'), def api_bitbucket2_webhook(request, user_profile, payload=REQ(argument_type='body'),
stream=REQ(default='bitbucket'), branches=REQ(default=None)): stream=REQ(default='bitbucket'), branches=REQ(default=None)):
# type: (HttpRequest, UserProfile, Dict[str, Any], str, Optional[Text]) -> HttpResponse # type: (HttpRequest, UserProfile, Dict[str, Any], str, Optional[Text]) -> HttpResponse
try: type = get_type(request, payload)
type = get_type(request, payload) if type != 'push':
if type != 'push': subject = get_subject_based_on_type(payload, type)
subject = get_subject_based_on_type(payload, type) body = get_body_based_on_type(type)(payload)
body = get_body_based_on_type(type)(payload) check_send_message(user_profile, request.client, 'stream', [stream], subject, body)
else:
branch = get_branch_name_for_push_event(payload)
if branch and branches:
if branches.find(branch) == -1:
return json_success()
subjects = get_push_subjects(payload)
bodies_list = get_push_bodies(payload)
for body, subject in zip(bodies_list, subjects):
check_send_message(user_profile, request.client, 'stream', [stream], subject, body) check_send_message(user_profile, request.client, 'stream', [stream], subject, body)
else:
branch = get_branch_name_for_push_event(payload)
if branch and branches:
if branches.find(branch) == -1:
return json_success()
subjects = get_push_subjects(payload)
bodies_list = get_push_bodies(payload)
for body, subject in zip(bodies_list, subjects):
check_send_message(user_profile, request.client, 'stream', [stream], subject, body)
except KeyError as e:
return json_error(_("Missing key {} in JSON").format(str(e)))
return json_success() return json_success()
def get_subject_for_branch_specified_events(payload, branch_name=None): def get_subject_for_branch_specified_events(payload, branch_name=None):

View File

@@ -29,12 +29,9 @@ CODESHIP_STATUS_MAPPER = {
def api_codeship_webhook(request, user_profile, payload=REQ(argument_type='body'), def api_codeship_webhook(request, user_profile, payload=REQ(argument_type='body'),
stream=REQ(default='codeship')): stream=REQ(default='codeship')):
# type: (HttpRequest, UserProfile, Dict[str, Any], str) -> HttpResponse # type: (HttpRequest, UserProfile, Dict[str, Any], str) -> HttpResponse
try: payload = payload['build']
payload = payload['build'] subject = get_subject_for_http_request(payload)
subject = get_subject_for_http_request(payload) body = get_body_for_http_request(payload)
body = get_body_for_http_request(payload)
except KeyError as e:
return json_error(_("Missing key {} in JSON").format(str(e)))
check_send_message(user_profile, request.client, 'stream', [stream], subject, body) check_send_message(user_profile, request.client, 'stream', [stream], subject, body)
return json_success() return json_success()

View File

@@ -22,23 +22,20 @@ VERIFICATION_EVENT = 'verification'
def api_crashlytics_webhook(request, user_profile, payload=REQ(argument_type='body'), def api_crashlytics_webhook(request, user_profile, payload=REQ(argument_type='body'),
stream=REQ(default='crashlytics')): stream=REQ(default='crashlytics')):
# type: (HttpRequest, UserProfile, Dict[str, Any], Text) -> HttpResponse # type: (HttpRequest, UserProfile, Dict[str, Any], Text) -> HttpResponse
try: event = payload['event']
event = payload['event'] if event == VERIFICATION_EVENT:
if event == VERIFICATION_EVENT: subject = CRASHLYTICS_SETUP_SUBJECT_TEMPLATE
subject = CRASHLYTICS_SETUP_SUBJECT_TEMPLATE body = CRASHLYTICS_SETUP_MESSAGE_TEMPLATE
body = CRASHLYTICS_SETUP_MESSAGE_TEMPLATE else:
else: issue_body = payload['payload']
issue_body = payload['payload'] subject = CRASHLYTICS_SUBJECT_TEMPLATE.format(
subject = CRASHLYTICS_SUBJECT_TEMPLATE.format( display_id=issue_body['display_id'],
display_id=issue_body['display_id'], title=issue_body['title']
title=issue_body['title'] )
) body = CRASHLYTICS_MESSAGE_TEMPLATE.format(
body = CRASHLYTICS_MESSAGE_TEMPLATE.format( impacted_devices_count=issue_body['impacted_devices_count'],
impacted_devices_count=issue_body['impacted_devices_count'], url=issue_body['url']
url=issue_body['url'] )
)
except KeyError as e:
return json_error(_("Missing key {} in JSON".format(str(e))))
check_send_message(user_profile, request.client, 'stream', [stream], check_send_message(user_profile, request.client, 'stream', [stream],
subject, body) subject, body)

View File

@@ -24,13 +24,10 @@ def api_delighted_webhook(request, user_profile,
stream=REQ(default='delighted'), stream=REQ(default='delighted'),
topic=REQ(default='Survey Response')): topic=REQ(default='Survey Response')):
# type: (HttpRequest, UserProfile, Dict[str, Dict[str, Any]], text_type, text_type) -> HttpResponse # type: (HttpRequest, UserProfile, Dict[str, Dict[str, Any]], text_type, text_type) -> HttpResponse
try: person = payload['event_data']['person']
person = payload['event_data']['person'] selected_payload = {'email': person['email']}
selected_payload = {'email': person['email']} selected_payload['score'] = payload['event_data']['score']
selected_payload['score'] = payload['event_data']['score'] selected_payload['comment'] = payload['event_data']['comment']
selected_payload['comment'] = payload['event_data']['comment']
except KeyError as e:
return json_error(_("Missing key {} in JSON").format(str(e)))
BODY_TEMPLATE = body_template(selected_payload['score']) BODY_TEMPLATE = body_template(selected_payload['score'])
body = BODY_TEMPLATE.format(**selected_payload) body = BODY_TEMPLATE.format(**selected_payload)

View File

@@ -133,11 +133,7 @@ def api_freshdesk_webhook(request, user_profile, payload=REQ(argument_type='body
ticket = TicketDict(ticket_data) ticket = TicketDict(ticket_data)
subject = "#%s: %s" % (ticket.id, ticket.subject) subject = "#%s: %s" % (ticket.id, ticket.subject)
event_info = parse_freshdesk_event(ticket.triggered_event)
try:
event_info = parse_freshdesk_event(ticket.triggered_event)
except ValueError:
return json_error(_("Malformed event %s") % (ticket.triggered_event,))
if event_info[1] == "created": if event_info[1] == "created":
content = format_freshdesk_ticket_creation_message(ticket) content = format_freshdesk_ticket_creation_message(ticket)

View File

@@ -71,35 +71,31 @@ def api_gogs_webhook(request, user_profile,
repo = payload['repository']['name'] repo = payload['repository']['name']
event = request.META['HTTP_X_GOGS_EVENT'] event = request.META['HTTP_X_GOGS_EVENT']
if event == 'push':
try: branch = payload['ref'].replace('refs/heads/', '')
if event == 'push': if branches is not None and branches.find(branch) == -1:
branch = payload['ref'].replace('refs/heads/', '') return json_success()
if branches is not None and branches.find(branch) == -1: body = format_push_event(payload)
return json_success() topic = SUBJECT_WITH_BRANCH_TEMPLATE.format(
body = format_push_event(payload) repo=repo,
topic = SUBJECT_WITH_BRANCH_TEMPLATE.format( branch=branch
repo=repo, )
branch=branch elif event == 'create':
) body = format_new_branch_event(payload)
elif event == 'create': topic = SUBJECT_WITH_BRANCH_TEMPLATE.format(
body = format_new_branch_event(payload) repo=repo,
topic = SUBJECT_WITH_BRANCH_TEMPLATE.format( branch=payload['ref']
repo=repo, )
branch=payload['ref'] elif event == 'pull_request':
) body = format_pull_request_event(payload)
elif event == 'pull_request': topic = SUBJECT_WITH_PR_OR_ISSUE_INFO_TEMPLATE.format(
body = format_pull_request_event(payload) repo=repo,
topic = SUBJECT_WITH_PR_OR_ISSUE_INFO_TEMPLATE.format( type='PR',
repo=repo, id=payload['pull_request']['id'],
type='PR', title=payload['pull_request']['title']
id=payload['pull_request']['id'], )
title=payload['pull_request']['title'] else:
) return json_error(_('Invalid event "{}" in request headers').format(event))
else:
return json_error(_('Invalid event "{}" in request headers').format(event))
except KeyError as e:
return json_error(_('Missing key {} in JSON').format(str(e)))
check_send_message(user_profile, request.client, 'stream', [stream], topic, body) check_send_message(user_profile, request.client, 'stream', [stream], topic, body)
return json_success() return json_success()

View File

@@ -18,14 +18,10 @@ def api_gosquared_webhook(request, user_profile,
stream=REQ(default='gosquared'), stream=REQ(default='gosquared'),
topic=REQ(default=None)): topic=REQ(default=None)):
# type: (HttpRequest, UserProfile, Dict[str, Dict[str, Any]], Text, Text) -> HttpResponse # type: (HttpRequest, UserProfile, Dict[str, Dict[str, Any]], Text, Text) -> HttpResponse
try: domain_name = payload['siteDetails']['domain']
domain_name = payload['siteDetails']['domain'] user_num = payload['concurrents']
user_num = payload['concurrents'] user_acc = payload['siteDetails']['acct']
user_acc = payload['siteDetails']['acct'] acc_url = 'https://www.gosquared.com/now/' + user_acc
acc_url = 'https://www.gosquared.com/now/' + user_acc
except KeyError as e:
return json_error(_("Missing key {} in JSON").format(str(e)))
body = BODY_TEMPLATE.format(website_name=domain_name, website_url=acc_url, user_num=user_num) body = BODY_TEMPLATE.format(website_name=domain_name, website_url=acc_url, user_num=user_num)
# allows for customisable topics # allows for customisable topics
if topic is None: if topic is None:

View File

@@ -40,25 +40,21 @@ def api_greenhouse_webhook(request, user_profile,
payload=REQ(argument_type='body'), payload=REQ(argument_type='body'),
stream=REQ(default='greenhouse'), topic=REQ(default=None)): stream=REQ(default='greenhouse'), topic=REQ(default=None)):
# type: (HttpRequest, UserProfile, Dict[str, Any], str, str) -> HttpResponse # type: (HttpRequest, UserProfile, Dict[str, Any], str, str) -> HttpResponse
try: if payload['action'] == 'update_candidate':
if payload['action'] == 'update_candidate': candidate = payload['payload']['candidate']
candidate = payload['payload']['candidate'] else:
else: candidate = payload['payload']['application']['candidate']
candidate = payload['payload']['application']['candidate'] action = payload['action'].replace('_', ' ').title()
action = payload['action'].replace('_', ' ').title() body = "{}\n>{} {}\nID: {}\n{}".format(
body = "{}\n>{} {}\nID: {}\n{}".format( action,
action, candidate['first_name'],
candidate['first_name'], candidate['last_name'],
candidate['last_name'], str(candidate['id']),
str(candidate['id']), message_creator(payload['action'],
message_creator(payload['action'], payload['payload']['application']))
payload['payload']['application']))
if topic is None: if topic is None:
topic = "{} - {}".format(action, str(candidate['id'])) topic = "{} - {}".format(action, str(candidate['id']))
except KeyError as e:
return json_error(_("Missing key {} in JSON").format(str(e)))
check_send_message(user_profile, request.client, 'stream', [stream], topic, body) check_send_message(user_profile, request.client, 'stream', [stream], topic, body)
return json_success() return json_success()

View File

@@ -48,12 +48,7 @@ def api_hellosign_webhook(request, user_profile,
stream=REQ(default='hellosign'), stream=REQ(default='hellosign'),
topic=REQ(default=None)): topic=REQ(default=None)):
# type: (HttpRequest, UserProfile, Dict[str, Dict[str, Any]], text_type, text_type) -> HttpResponse # type: (HttpRequest, UserProfile, Dict[str, Dict[str, Any]], text_type, text_type) -> HttpResponse
try: model_payload = ready_payload(payload['signature_request']['signatures'], payload)
model_payload = ready_payload(payload['signature_request']['signatures'],
payload)
except KeyError as e:
return json_error(_("Missing key {} in JSON").format(str(e)))
body = format_body(payload['signature_request']['signatures'], model_payload) body = format_body(payload['signature_request']['signatures'], model_payload)
topic = topic or model_payload['contract_title'] topic = topic or model_payload['contract_title']
check_send_message(user_profile, request.client, 'stream', [stream], check_send_message(user_profile, request.client, 'stream', [stream],

View File

@@ -21,12 +21,8 @@ def api_helloworld_webhook(request, user_profile,
body = 'Hello! I am happy to be here! :smile:' body = 'Hello! I am happy to be here! :smile:'
# try to add the Wikipedia article of the day # try to add the Wikipedia article of the day
# return appropriate error if not successful body_template = '\nThe Wikipedia featured article for today is **[{featured_title}]({featured_url})**'
try: body += body_template.format(**payload)
body_template = '\nThe Wikipedia featured article for today is **[{featured_title}]({featured_url})**'
body += body_template.format(**payload)
except KeyError as e:
return json_error(_("Missing key {} in JSON").format(str(e)))
# send the message # send the message
check_send_message(user_profile, request.client, 'stream', [stream], topic, body) check_send_message(user_profile, request.client, 'stream', [stream], topic, body)

View File

@@ -18,10 +18,7 @@ def api_homeassistant_webhook(request, user_profile,
# type: (HttpRequest, UserProfile, Dict[str, str], Text) -> HttpResponse # type: (HttpRequest, UserProfile, Dict[str, str], Text) -> HttpResponse
# construct the body of the message # construct the body of the message
try: body = payload["message"]
body = payload["message"]
except KeyError as e:
return json_error(_("Missing key {} in JSON").format(str(e)))
# set the topic to the topic parameter, if given # set the topic to the topic parameter, if given
if "topic" in payload: if "topic" in payload:

View File

@@ -17,14 +17,9 @@ def api_mention_webhook(request, user_profile,
stream=REQ(default='mention'), stream=REQ(default='mention'),
topic=REQ(default='news')): topic=REQ(default='news')):
# type: (HttpRequest, UserProfile, Dict[str, Iterable[Dict[str, Any]]], Text, Optional[Text]) -> HttpResponse # type: (HttpRequest, UserProfile, Dict[str, Iterable[Dict[str, Any]]], Text, Optional[Text]) -> HttpResponse
title = payload["title"]
try: source_url = payload["url"]
title = payload["title"] description = payload["description"]
source_url = payload["url"]
description = payload["description"]
except KeyError as e:
return json_error(_("Missing key {} in JSON").format(str(e)))
# construct the body of the message # construct the body of the message
body = '**[%s](%s)**:\n%s' % (title, source_url, description) body = '**[%s](%s)**:\n%s' % (title, source_url, description)

View File

@@ -41,14 +41,11 @@ def api_opsgenie_webhook(request, user_profile,
if 'message' in payload['alert']: if 'message' in payload['alert']:
info['additional_info'] += "Message: *{}*\n".format(payload['alert']['message']) info['additional_info'] += "Message: *{}*\n".format(payload['alert']['message'])
body = '' body = ''
try: body_template = "**OpsGenie: [Alert for {integration_name}.](https://app.opsgenie.com/alert/V2#/show/{alert_id})**\n" \
body_template = "**OpsGenie: [Alert for {integration_name}.](https://app.opsgenie.com/alert/V2#/show/{alert_id})**\n" \ "Type: *{alert_type}*\n" \
"Type: *{alert_type}*\n" \ "{additional_info}" \
"{additional_info}" \ "{tags}"
"{tags}" body += body_template.format(**info)
body += body_template.format(**info)
except KeyError as e:
return json_error(_("Missing key {} in JSON").format(str(e)))
# send the message # send the message
check_send_message(user_profile, request.client, 'stream', [stream], topic, body) check_send_message(user_profile, request.client, 'stream', [stream], topic, body)

View File

@@ -19,25 +19,22 @@ def api_papertrail_webhook(request, user_profile,
# type: (HttpRequest, UserProfile, Dict[str, Any], Text, Text) -> HttpResponse # type: (HttpRequest, UserProfile, Dict[str, Any], Text, Text) -> HttpResponse
# construct the message of the message # construct the message of the message
try: message_template = '**"{}"** search found **{}** matches - {}\n```'
message_template = '**"{}"** search found **{}** matches - {}\n```' message = [message_template.format(payload["saved_search"]["name"],
message = [message_template.format(payload["saved_search"]["name"], str(len(payload["events"])),
str(len(payload["events"])), payload["saved_search"]["html_search_url"])]
payload["saved_search"]["html_search_url"])] for i, event in enumerate(payload["events"]):
for i, event in enumerate(payload["events"]): event_text = '{} {} {}:\n {}'.format(event["display_received_at"],
event_text = '{} {} {}:\n {}'.format(event["display_received_at"], event["source_name"],
event["source_name"], payload["saved_search"]["query"],
payload["saved_search"]["query"], event["message"])
event["message"]) message.append(event_text)
message.append(event_text) if i >= 3:
if i >= 3: message.append('```\n[See more]({})'.format(payload["saved_search"]["html_search_url"]))
message.append('```\n[See more]({})'.format(payload["saved_search"]["html_search_url"])) break
break else:
else: message.append('```')
message.append('```') post = '\n'.join(message)
post = '\n'.join(message)
except KeyError as e:
return json_error(_("Missing key {} in JSON").format(str(e)))
# send the message # send the message
check_send_message(user_profile, request.client, 'stream', [stream], topic, post) check_send_message(user_profile, request.client, 'stream', [stream], topic, post)

View File

@@ -167,14 +167,9 @@ def api_pivotal_webhook(request, user_profile, stream=REQ()):
subject = content = None subject = content = None
try: try:
subject, content = api_pivotal_webhook_v3(request, user_profile, stream) subject, content = api_pivotal_webhook_v3(request, user_profile, stream)
except AttributeError:
return json_error(_("Failed to extract data from Pivotal XML response"))
except Exception: except Exception:
# Attempt to parse v5 JSON payload # Attempt to parse v5 JSON payload
try: subject, content = api_pivotal_webhook_v5(request, user_profile, stream)
subject, content = api_pivotal_webhook_v5(request, user_profile, stream)
except AttributeError:
return json_error(_("Failed to extract data from Pivotal V5 JSON response"))
if subject is None or content is None: if subject is None or content is None:
return json_error(_("Unable to handle Pivotal payload")) return json_error(_("Unable to handle Pivotal payload"))

View File

@@ -23,35 +23,26 @@ def api_semaphore_webhook(request, user_profile,
# semaphore only gives the last commit, even if there were multiple commits # semaphore only gives the last commit, even if there were multiple commits
# since the last build # since the last build
try: branch_name = payload["branch_name"]
branch_name = payload["branch_name"] project_name = payload["project_name"]
project_name = payload["project_name"] result = payload["result"]
result = payload["result"] event = payload["event"]
event = payload["event"] commit_id = payload["commit"]["id"]
commit_id = payload["commit"]["id"] commit_url = payload["commit"]["url"]
commit_url = payload["commit"]["url"] author_email = payload["commit"]["author_email"]
author_email = payload["commit"]["author_email"] message = payload["commit"]["message"]
message = payload["commit"]["message"]
except KeyError as e:
return json_error(_("Missing key %s in JSON") % (str(e),))
if event == "build": if event == "build":
try: build_url = payload["build_url"]
build_url = payload["build_url"] build_number = payload["build_number"]
build_number = payload["build_number"]
except KeyError as e:
return json_error(_("Missing key %s in JSON") % (str(e),))
content = u"[build %s](%s): %s\n" % (build_number, build_url, result) content = u"[build %s](%s): %s\n" % (build_number, build_url, result)
elif event == "deploy": elif event == "deploy":
try: build_url = payload["build_html_url"]
build_url = payload["build_html_url"] build_number = payload["build_number"]
build_number = payload["build_number"] deploy_url = payload["html_url"]
deploy_url = payload["html_url"] deploy_number = payload["number"]
deploy_number = payload["number"] server_name = payload["server_name"]
server_name = payload["server_name"]
except KeyError as e:
return json_error(_("Missing key %s in JSON") % (str(e),))
content = u"[deploy %s](%s) of [build %s](%s) on server %s: %s\n" % \ content = u"[deploy %s](%s) of [build %s](%s) on server %s: %s\n" % \
(deploy_number, deploy_url, build_number, build_url, server_name, result) (deploy_number, deploy_url, build_number, build_url, server_name, result)

View File

@@ -23,16 +23,13 @@ def api_solano_webhook(request, user_profile,
if event == 'test': if event == 'test':
return handle_test_event(user_profile, request.client, stream, topic) return handle_test_event(user_profile, request.client, stream, topic)
try: try:
try: author = payload['committers'][0]
author = payload['committers'][0] except KeyError:
except KeyError: author = 'Unknown'
author = 'Unknown' status = payload['status']
status = payload['status'] build_log = payload['url']
build_log = payload['url'] repository = payload['repository']['url']
repository = payload['repository']['url'] commit_id = payload['commit_id']
commit_id = payload['commit_id']
except KeyError as e:
return json_error(_('Missing key {} in JSON').format(str(e)))
good_status = ['passed'] good_status = ['passed']
bad_status = ['failed', 'error'] bad_status = ['failed', 'error']

View File

@@ -20,145 +20,142 @@ def api_stripe_webhook(request, user_profile,
# type: (HttpRequest, UserProfile, Dict[str, Any], Text, Optional[Text]) -> HttpResponse # type: (HttpRequest, UserProfile, Dict[str, Any], Text, Optional[Text]) -> HttpResponse
body = None body = None
event_type = payload["type"] event_type = payload["type"]
try: data_object = payload["data"]["object"]
data_object = payload["data"]["object"] if event_type.startswith('charge'):
if event_type.startswith('charge'):
charge_url = "https://dashboard.stripe.com/payments/{}" charge_url = "https://dashboard.stripe.com/payments/{}"
amount_string = amount(payload["data"]["object"]["amount"], payload["data"]["object"]["currency"]) amount_string = amount(payload["data"]["object"]["amount"], payload["data"]["object"]["currency"])
if event_type.startswith('charge.dispute'): if event_type.startswith('charge.dispute'):
charge_id = data_object["charge"] charge_id = data_object["charge"]
link = charge_url.format(charge_id) link = charge_url.format(charge_id)
body_template = "A charge dispute for **{amount}** has been {rest}.\n"\ body_template = "A charge dispute for **{amount}** has been {rest}.\n"\
"The charge in dispute {verb} **[{charge}]({link})**." "The charge in dispute {verb} **[{charge}]({link})**."
if event_type == "charge.dispute.closed": if event_type == "charge.dispute.closed":
rest = "closed as **{}**".format(data_object['status']) rest = "closed as **{}**".format(data_object['status'])
verb = 'was' verb = 'was'
else:
rest = "created"
verb = 'is'
body = body_template.format(amount=amount_string, rest=rest, verb=verb, charge=charge_id, link=link)
else:
charge_id = data_object["id"]
link = charge_url.format(charge_id)
body_template = "A charge with id **[{charge_id}]({link})** for **{amount}** has {verb}."
if event_type == "charge.failed":
verb = "failed"
else:
verb = "succeeded"
body = body_template.format(charge_id=charge_id, link=link, amount=amount_string, verb=verb)
if topic is None:
topic = "Charge {}".format(charge_id)
elif event_type.startswith('customer'):
object_id = data_object["id"]
if event_type.startswith('customer.subscription'):
link = "https://dashboard.stripe.com/subscriptions/{}".format(object_id)
if event_type == "customer.subscription.created":
amount_string = amount(data_object["plan"]["amount"], data_object["plan"]["currency"])
body_template = "A new customer subscription for **{amount}** " \
"every **{interval}** has been created.\n" \
"The subscription has id **[{id}]({link})**."
body = body_template.format(
amount=amount_string,
interval=data_object['plan']['interval'],
id=object_id,
link=link
)
elif event_type == "customer.subscription.deleted":
body_template = "The customer subscription with id **[{id}]({link})** was deleted."
body = body_template.format(id=object_id, link=link)
else: # customer.subscription.trial_will_end
DAY = 60 * 60 * 24 # seconds in a day
# days_left should always be three according to
# https://stripe.com/docs/api/python#event_types, but do the
# computation just to be safe.
days_left = int((data_object["trial_end"] - time.time() + DAY//2) // DAY)
body_template = "The customer subscription trial with id **[{id}]({link})** will end in {days} days."
body = body_template.format(id=object_id, link=link, days=days_left)
else:
link = "https://dashboard.stripe.com/customers/{}".format(object_id)
body_template = "{beginning} customer with id **[{id}]({link})** {rest}."
if event_type == "customer.created":
beginning = "A new"
if data_object["email"] is None:
rest = "has been created"
else: else:
rest = "created" rest = "and email **{}** has been created".format(data_object['email'])
verb = 'is'
body = body_template.format(amount=amount_string, rest=rest, verb=verb, charge=charge_id, link=link)
else: else:
charge_id = data_object["id"] beginning = "A"
link = charge_url.format(charge_id) rest = "has been deleted"
body_template = "A charge with id **[{charge_id}]({link})** for **{amount}** has {verb}." body = body_template.format(beginning=beginning, id=object_id, link=link, rest=rest)
if event_type == "charge.failed": if topic is None:
verb = "failed" topic = "Customer {}".format(object_id)
else:
verb = "succeeded"
body = body_template.format(charge_id=charge_id, link=link, amount=amount_string, verb=verb)
if topic is None: elif event_type == "invoice.payment_failed":
topic = "Charge {}".format(charge_id) object_id = data_object['id']
link = "https://dashboard.stripe.com/invoices/{}".format(object_id)
amount_string = amount(data_object["amount_due"], data_object["currency"])
body_template = "An invoice payment on invoice with id **[{id}]({link})** and "\
"with **{amount}** due has failed."
body = body_template.format(id=object_id, amount=amount_string, link=link)
elif event_type.startswith('customer'): if topic is None:
object_id = data_object["id"] topic = "Invoice {}".format(object_id)
if event_type.startswith('customer.subscription'):
link = "https://dashboard.stripe.com/subscriptions/{}".format(object_id)
if event_type == "customer.subscription.created": elif event_type.startswith('order'):
amount_string = amount(data_object["plan"]["amount"], data_object["plan"]["currency"]) object_id = data_object['id']
link = "https://dashboard.stripe.com/orders/{}".format(object_id)
amount_string = amount(data_object["amount"], data_object["currency"])
body_template = "{beginning} order with id **[{id}]({link})** for **{amount}** has {end}."
body_template = "A new customer subscription for **{amount}** " \ if event_type == "order.payment_failed":
"every **{interval}** has been created.\n" \ beginning = "An order payment on"
"The subscription has id **[{id}]({link})**." end = "failed"
body = body_template.format( elif event_type == "order.payment_succeeded":
amount=amount_string, beginning = "An order payment on"
interval=data_object['plan']['interval'], end = "succeeded"
id=object_id, else:
link=link beginning = "The"
) end = "been updated"
elif event_type == "customer.subscription.deleted": body = body_template.format(beginning=beginning, id=object_id, link=link, amount=amount_string, end=end)
body_template = "The customer subscription with id **[{id}]({link})** was deleted."
body = body_template.format(id=object_id, link=link)
else: # customer.subscription.trial_will_end if topic is None:
DAY = 60 * 60 * 24 # seconds in a day topic = "Order {}".format(object_id)
# days_left should always be three according to
# https://stripe.com/docs/api/python#event_types, but do the
# computation just to be safe.
days_left = int((data_object["trial_end"] - time.time() + DAY//2) // DAY)
body_template = "The customer subscription trial with id **[{id}]({link})** will end in {days} days."
body = body_template.format(id=object_id, link=link, days=days_left)
else: elif event_type.startswith('transfer'):
link = "https://dashboard.stripe.com/customers/{}".format(object_id) object_id = data_object['id']
body_template = "{beginning} customer with id **[{id}]({link})** {rest}." link = "https://dashboard.stripe.com/transfers/{}".format(object_id)
amount_string = amount(data_object["amount"], data_object["currency"])
body_template = "The transfer with description **{description}** and id **[{id}]({link})** " \
"for amount **{amount}** has {end}."
if event_type == "transfer.failed":
end = 'failed'
else:
end = "been paid"
body = body_template.format(
description=data_object['description'],
id=object_id,
link=link,
amount=amount_string,
end=end
)
if event_type == "customer.created": if topic is None:
beginning = "A new" topic = "Transfer {}".format(object_id)
if data_object["email"] is None:
rest = "has been created"
else:
rest = "and email **{}** has been created".format(data_object['email'])
else:
beginning = "A"
rest = "has been deleted"
body = body_template.format(beginning=beginning, id=object_id, link=link, rest=rest)
if topic is None:
topic = "Customer {}".format(object_id)
elif event_type == "invoice.payment_failed":
object_id = data_object['id']
link = "https://dashboard.stripe.com/invoices/{}".format(object_id)
amount_string = amount(data_object["amount_due"], data_object["currency"])
body_template = "An invoice payment on invoice with id **[{id}]({link})** and "\
"with **{amount}** due has failed."
body = body_template.format(id=object_id, amount=amount_string, link=link)
if topic is None:
topic = "Invoice {}".format(object_id)
elif event_type.startswith('order'):
object_id = data_object['id']
link = "https://dashboard.stripe.com/orders/{}".format(object_id)
amount_string = amount(data_object["amount"], data_object["currency"])
body_template = "{beginning} order with id **[{id}]({link})** for **{amount}** has {end}."
if event_type == "order.payment_failed":
beginning = "An order payment on"
end = "failed"
elif event_type == "order.payment_succeeded":
beginning = "An order payment on"
end = "succeeded"
else:
beginning = "The"
end = "been updated"
body = body_template.format(beginning=beginning, id=object_id, link=link, amount=amount_string, end=end)
if topic is None:
topic = "Order {}".format(object_id)
elif event_type.startswith('transfer'):
object_id = data_object['id']
link = "https://dashboard.stripe.com/transfers/{}".format(object_id)
amount_string = amount(data_object["amount"], data_object["currency"])
body_template = "The transfer with description **{description}** and id **[{id}]({link})** " \
"for amount **{amount}** has {end}."
if event_type == "transfer.failed":
end = 'failed'
else:
end = "been paid"
body = body_template.format(
description=data_object['description'],
id=object_id,
link=link,
amount=amount_string,
end=end
)
if topic is None:
topic = "Transfer {}".format(object_id)
except KeyError as e:
return json_error(_("Missing key {} in JSON".format(str(e))))
if body is None: if body is None:
return json_error(_("We don't support {} event".format(event_type))) return json_error(_("We don't support {} event".format(event_type)))

View File

@@ -252,10 +252,7 @@ def parse_message(message):
def generate_content(data): def generate_content(data):
# type: (Mapping[str, Any]) -> str # type: (Mapping[str, Any]) -> str
""" Gets the template string and formats it with parsed data. """ """ Gets the template string and formats it with parsed data. """
try: return templates[data['type']][data['event']] % data['values']
return templates[data['type']][data['event']] % data['values']
except KeyError:
return json_error(_("Unknown message"))
def get_owner_name(message): def get_owner_name(message):
# type: (Mapping[str, Any]) -> str # type: (Mapping[str, Any]) -> str

View File

@@ -16,12 +16,9 @@ SUBJECT_TEMPLATE = "{service_url}"
def send_message_for_event(event, user_profile, client, stream): def send_message_for_event(event, user_profile, client, stream):
# type: (Dict[str, Any], UserProfile, Client, str) -> None # type: (Dict[str, Any], UserProfile, Client, str) -> None
try: event_type = get_event_type(event)
event_type = get_event_type(event) subject = SUBJECT_TEMPLATE.format(service_url=event['check']['url'])
subject = SUBJECT_TEMPLATE.format(service_url=event['check']['url']) body = EVENT_TYPE_BODY_MAPPER[event_type](event)
body = EVENT_TYPE_BODY_MAPPER[event_type](event)
except KeyError as e:
return json_error(_("Missing key {} in JSON").format(str(e)))
check_send_message(user_profile, client, 'stream', [stream], subject, body) check_send_message(user_profile, client, 'stream', [stream], subject, body)
def get_body_for_up_event(event): def get_body_for_up_event(event):