mirror of
https://github.com/zulip/zulip.git
synced 2025-11-16 03:41:58 +00:00
Don't handle json payload key errors inside webhooks.
Fixes first part of #6213.
This commit is contained in:
@@ -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.
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|
||||||
|
|||||||
@@ -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))
|
||||||
|
|||||||
@@ -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):
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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],
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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"))
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
|
|||||||
@@ -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']
|
||||||
|
|||||||
@@ -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)))
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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):
|
||||||
|
|||||||
Reference in New Issue
Block a user