webhooks: Remove repetitive argument to UnsupportedWebhookEventType.

The name of the webhook can be added by the webhook decorator.
This commit is contained in:
Alex Vandiver 2020-08-19 15:50:06 -07:00 committed by Tim Abbott
parent e2ab7b9e17
commit d04db7c5fe
30 changed files with 55 additions and 53 deletions

View File

@ -619,15 +619,13 @@ webhook bot, notifying them of the missing header.
### Handling unexpected webhook event types
Many third-party services have dozens of different event types. In some cases, we
may choose to explicitly ignore specific events. In other cases, there may be
events that are new or events that we don't know about. In such cases, we
recommend raising `UnsupportedWebhookEventType` (found in
`zerver/lib/exceptions.py`), like so:
Many third-party services have dozens of different event types. In
some cases, we may choose to explicitly ignore specific events. In
other cases, there may be events that are new or events that we don't
know about. In such cases, we recommend raising
`UnsupportedWebhookEventType` (found in `zerver/lib/exceptions.py`),
with a string describing the unsupported event type, like so:
```
raise UnsupportedWebhookEventType(webhook_name, event_type)
raise UnsupportedWebhookEventType(event_type)
```
`webhook_name` is the name of the integration that raises the exception.
`event_type` is the name of the unexpected webhook event.

View File

@ -348,6 +348,8 @@ def webhook_view(
from zerver.lib.webhooks.common import notify_bot_owner_about_invalid_json
notify_bot_owner_about_invalid_json(user_profile, webhook_client_name)
else:
if isinstance(err, UnsupportedWebhookEventType):
err.webhook_name = webhook_client_name
log_exception_to_webhook_logger(
request=request,
user_profile=user_profile,
@ -597,6 +599,8 @@ def authenticated_rest_api_view(
return target_view_func(request, profile, *args, **kwargs)
except Exception as err:
if is_webhook or webhook_client_name is not None:
if isinstance(err, UnsupportedWebhookEventType) and webhook_client_name is not None:
err.webhook_name = webhook_client_name
request_body = request.POST.get('payload')
if request_body is not None:
log_exception_to_webhook_logger(

View File

@ -261,8 +261,8 @@ class UnsupportedWebhookEventType(JsonableError):
code = ErrorCode.UNSUPPORTED_WEBHOOK_EVENT_TYPE
data_fields = ['webhook_name', 'event_type']
def __init__(self, webhook_name: str, event_type: Optional[str]) -> None:
self.webhook_name = webhook_name
def __init__(self, event_type: Optional[str]) -> None:
self.webhook_name = "(unknown)"
self.event_type = event_type
@staticmethod

View File

@ -271,7 +271,7 @@ class DecoratorTestCase(ZulipTestCase):
@webhook_view('ClientName')
def my_webhook_raises_exception_unsupported_event(
request: HttpRequest, user_profile: UserProfile) -> None:
raise UnsupportedWebhookEventType("helloworld", "test_event")
raise UnsupportedWebhookEventType("test_event")
webhook_bot_email = 'webhook-bot@zulip.com'
webhook_bot_realm = get_realm('zulip')
@ -363,7 +363,7 @@ body:
# Test when an unsupported webhook event occurs
with mock.patch('zerver.decorator.webhook_unsupported_events_logger.exception') as mock_exception:
exception_msg = "The 'test_event' event isn't currently supported by the helloworld webhook"
exception_msg = "The 'test_event' event isn't currently supported by the ClientName webhook"
with self.assertRaisesRegex(UnsupportedWebhookEventType, exception_msg):
request.body = "invalidjson"
request.content_type = 'application/json'
@ -543,7 +543,7 @@ body:
def test_authenticated_rest_api_view_logging_unsupported_event(self) -> None:
@authenticated_rest_api_view(webhook_client_name="ClientName")
def my_webhook_raises_exception(request: HttpRequest, user_profile: UserProfile) -> None:
raise UnsupportedWebhookEventType("helloworld", "test_event")
raise UnsupportedWebhookEventType("test_event")
webhook_bot_email = 'webhook-bot@zulip.com'
webhook_bot_realm = get_realm('zulip')
@ -558,7 +558,7 @@ body:
request.content_type = 'text/plain'
with mock.patch('zerver.decorator.webhook_unsupported_events_logger.exception') as mock_exception:
exception_msg = "The 'test_event' event isn't currently supported by the helloworld webhook"
exception_msg = "The 'test_event' event isn't currently supported by the ClientName webhook"
with self.assertRaisesRegex(UnsupportedWebhookEventType, exception_msg):
my_webhook_raises_exception(request)

View File

@ -30,7 +30,7 @@ def api_basecamp_webhook(request: HttpRequest, user_profile: UserProfile,
event = get_event_type(payload)
if event not in SUPPORT_EVENTS:
raise UnsupportedWebhookEventType('Basecamp', event)
raise UnsupportedWebhookEventType(event)
subject = get_project_name(payload)
if event.startswith('document_'):
@ -48,7 +48,7 @@ def api_basecamp_webhook(request: HttpRequest, user_profile: UserProfile,
elif event.startswith('comment_'):
body = get_comment_body(event, payload)
else:
raise UnsupportedWebhookEventType('Basecamp', event)
raise UnsupportedWebhookEventType(event)
check_send_webhook_message(request, user_profile, subject, body)
return json_success()

View File

@ -161,7 +161,7 @@ def get_type(request: HttpRequest, payload: Dict[str, Any]) -> str:
if event_key == 'repo:updated':
return event_key
raise UnsupportedWebhookEventType('BitBucket2', event_key)
raise UnsupportedWebhookEventType(event_key)
def get_body_based_on_type(type: str) -> Any:
fn = GET_SINGLE_MESSAGE_BODY_DEPENDING_ON_TYPE_MAPPER.get(type)

View File

@ -134,7 +134,7 @@ def repo_push_branch_data(payload: Dict[str, Any], change: Dict[str, Any]) -> Di
body = get_remove_branch_event_message(user_name, branch_name)
else:
message = "{}.{}".format(payload["eventKey"], event_type) # nocoverage
raise UnsupportedWebhookEventType("BitBucket Server", message)
raise UnsupportedWebhookEventType(message)
subject = TOPIC_WITH_BRANCH_TEMPLATE.format(repo=repo_name, branch=branch_name)
return {"subject": subject, "body": body}
@ -150,7 +150,7 @@ def repo_push_tag_data(payload: Dict[str, Any], change: Dict[str, Any]) -> Dict[
action = "removed"
else:
message = "{}.{}".format(payload["eventKey"], event_type) # nocoverage
raise UnsupportedWebhookEventType("BitBucket Server", message)
raise UnsupportedWebhookEventType(message)
subject = BITBUCKET_TOPIC_TEMPLATE.format(repository_name=repo_name)
body = get_push_tag_event_message(get_user_name(payload), tag_name, action=action)
@ -171,7 +171,7 @@ def repo_push_handler(payload: Dict[str, Any], branches: Optional[str]=None,
data.append(repo_push_tag_data(payload, change))
else:
message = "{}.{}".format(payload["eventKey"], event_target_type) # nocoverage
raise UnsupportedWebhookEventType("BitBucket Server", message)
raise UnsupportedWebhookEventType(message)
return data
def get_assignees_string(pr: Dict[str, Any]) -> Optional[str]:
@ -351,7 +351,7 @@ def get_event_handler(eventkey: str) -> Callable[..., List[Dict[str, str]]]:
# The main reason for this function existence is because of mypy
handler: Any = EVENT_HANDLER_MAP.get(eventkey)
if handler is None:
raise UnsupportedWebhookEventType("BitBucket Server", eventkey)
raise UnsupportedWebhookEventType(eventkey)
return handler
@webhook_view("Bitbucket3")

View File

@ -534,7 +534,7 @@ def api_clubhouse_webhook(
body_func: Any = EVENT_BODY_FUNCTION_MAPPER.get(event)
topic_func = get_topic_function_based_on_type(payload)
if body_func is None or topic_func is None:
raise UnsupportedWebhookEventType('Clubhouse', event)
raise UnsupportedWebhookEventType(event)
topic = topic_func(payload)
body = body_func(payload)

View File

@ -620,7 +620,7 @@ def api_github_webhook(
"""
header_event = validate_extract_webhook_http_header(request, "X_GITHUB_EVENT", "GitHub")
if header_event is None:
raise UnsupportedWebhookEventType("GitHub", "no header provided")
raise UnsupportedWebhookEventType("no header provided")
event = get_zulip_event_name(header_event, payload, branches)
if event is None:
@ -691,11 +691,11 @@ def get_zulip_event_name(
else:
# this means GH has actually added new actions since September 2020,
# so it's a bit more cause for alarm
raise UnsupportedWebhookEventType("GitHub", f"unsupported team action {action}")
raise UnsupportedWebhookEventType(f"unsupported team action {action}")
elif header_event in list(EVENT_FUNCTION_MAPPER.keys()):
return header_event
elif header_event in IGNORED_EVENTS:
return None
complete_event = "{}:{}".format(header_event, payload.get("action", "???")) # nocoverage
raise UnsupportedWebhookEventType('GitHub', complete_event)
raise UnsupportedWebhookEventType(complete_event)

View File

@ -452,4 +452,4 @@ def get_event(request: HttpRequest, payload: Dict[str, Any], branches: Optional[
if event in list(EVENT_FUNCTION_MAPPER.keys()):
return event
raise UnsupportedWebhookEventType('GitLab', event)
raise UnsupportedWebhookEventType(event)

View File

@ -197,7 +197,7 @@ def gogs_webhook_main(integration_name: str, http_header_name: str,
)
else:
raise UnsupportedWebhookEventType('Gogs', event)
raise UnsupportedWebhookEventType(event)
check_send_webhook_message(request, user_profile, topic, body)
return json_success()

View File

@ -55,6 +55,6 @@ def api_gosquared_webhook(request: HttpRequest, user_profile: UserProfile,
)
check_send_webhook_message(request, user_profile, topic, body)
else:
raise UnsupportedWebhookEventType('GoSquared', 'unknown_event')
raise UnsupportedWebhookEventType('unknown_event')
return json_success()

View File

@ -79,7 +79,7 @@ def get_event_handler(event: str) -> Callable[..., str]:
# The main reason for this function existence is because of mypy
handler: Any = EVENTS_FUNCTION_MAPPER.get(event)
if handler is None:
raise UnsupportedWebhookEventType("Groove", event)
raise UnsupportedWebhookEventType(event)
return handler
@webhook_view('Groove')

View File

@ -107,7 +107,7 @@ def api_harbor_webhook(request: HttpRequest, user_profile: UserProfile,
content_func = EVENT_FUNCTION_MAPPER.get(event)
if content_func is None:
raise UnsupportedWebhookEventType('Harbor', event)
raise UnsupportedWebhookEventType(event)
content: str = content_func(payload, user_profile, operator_username)

View File

@ -279,7 +279,7 @@ EVENT_TO_FUNCTION_MAPPER = {
def get_event_handler(event_type: str) -> Callable[..., Tuple[str, str]]:
handler: Any = EVENT_TO_FUNCTION_MAPPER.get(event_type)
if handler is None:
raise UnsupportedWebhookEventType("Intercom", event_type)
raise UnsupportedWebhookEventType(event_type)
return handler
@webhook_view('Intercom')

View File

@ -328,7 +328,7 @@ def api_jira_webhook(request: HttpRequest, user_profile: UserProfile,
content_func = get_event_handler(event)
if content_func is None:
raise UnsupportedWebhookEventType('Jira', event)
raise UnsupportedWebhookEventType(event)
subject = get_issue_subject(payload)
content: str = content_func(payload, user_profile)

View File

@ -51,4 +51,4 @@ def get_template(request: HttpRequest, payload: Dict[str, Any]) -> str:
elif event in EVENTS:
return message_template + 'is now {state}.'.format(state=payload['state'])
else:
raise UnsupportedWebhookEventType('Netlify', event)
raise UnsupportedWebhookEventType(event)

View File

@ -43,7 +43,7 @@ def api_newrelic_webhook(request: HttpRequest, user_profile: UserProfile,
subject = "{} deploy".format(deployment['application_name'])
content = DEPLOY_TEMPLATE.format(**deployment)
else:
raise UnsupportedWebhookEventType('New Relic', 'Unknown Event Type')
raise UnsupportedWebhookEventType('Unknown Event Type')
check_send_webhook_message(request, user_profile, subject, content)
return json_success()

View File

@ -172,7 +172,7 @@ def api_pagerduty_webhook(
break
if message_type not in PAGER_DUTY_EVENT_NAMES:
raise UnsupportedWebhookEventType('Pagerduty', message_type)
raise UnsupportedWebhookEventType(message_type)
format_dict = build_pagerduty_formatdict(message)
send_formated_pagerduty(request, user_profile, message_type, format_dict)
@ -186,7 +186,7 @@ def api_pagerduty_webhook(
break
if event not in PAGER_DUTY_EVENT_NAMES_V2:
raise UnsupportedWebhookEventType('Pagerduty', event)
raise UnsupportedWebhookEventType(event)
format_dict = build_pagerduty_formatdict_v2(message)
send_formated_pagerduty(request, user_profile, event, format_dict)

View File

@ -47,7 +47,7 @@ def api_pingdom_webhook(request: HttpRequest, user_profile: UserProfile,
subject = get_subject_for_http_request(payload)
body = get_body_for_http_request(payload)
else:
raise UnsupportedWebhookEventType('Pingdom', check_type)
raise UnsupportedWebhookEventType(check_type)
check_send_webhook_message(request, user_profile, subject, body)
return json_success()

View File

@ -152,7 +152,7 @@ def api_pivotal_webhook_v5(request: HttpRequest, user_profile: UserProfile) -> T
# Known but unsupported Pivotal event types
pass
else:
raise UnsupportedWebhookEventType('Pivotal Tracker', event_type)
raise UnsupportedWebhookEventType(event_type)
return subject, content

View File

@ -31,7 +31,7 @@ def api_raygun_webhook(request: HttpRequest, user_profile: UserProfile,
elif event == 'error_activity':
message = compose_activity_message(payload)
else:
raise UnsupportedWebhookEventType('Raygun', event)
raise UnsupportedWebhookEventType(event)
topic = 'test'
@ -220,7 +220,7 @@ def compose_notification_message(payload: Dict[str, Any]) -> str:
elif "FollowUp" in event_type:
return notification_message_follow_up(payload)
else:
raise UnsupportedWebhookEventType('Raygun', event_type)
raise UnsupportedWebhookEventType(event_type)
def activity_message(payload: Dict[str, Any]) -> str:
@ -276,7 +276,7 @@ def compose_activity_message(payload: Dict[str, Any]) -> str:
or event_type == "CommentAdded":
return activity_message(payload)
else:
raise UnsupportedWebhookEventType('Raygun', event_type)
raise UnsupportedWebhookEventType(event_type)
def parse_time(timestamp: str) -> str:

View File

@ -180,6 +180,6 @@ def api_reviewboard_webhook(
topic = get_review_request_repo_title(payload)
check_send_webhook_message(request, user_profile, topic, body)
else:
raise UnsupportedWebhookEventType('ReviewBoard', event_type)
raise UnsupportedWebhookEventType(event_type)
return json_success()

View File

@ -92,7 +92,7 @@ def handle_event_payload(event: Dict[str, Any]) -> Tuple[str, str]:
# We shouldn't support the officially deprecated Raven series of SDKs.
if int(event["version"]) < 7:
raise UnsupportedWebhookEventType("Sentry", "Raven SDK")
raise UnsupportedWebhookEventType("Raven SDK")
platform_name = event["platform"]
syntax_highlight_as = syntax_highlight_as_map.get(platform_name, "")
@ -155,7 +155,7 @@ def handle_event_payload(event: Dict[str, Any]) -> Tuple[str, str]:
body = MESSAGE_EVENT_TEMPLATE.format(**context)
else:
raise UnsupportedWebhookEventType("Sentry", "unknown-event type")
raise UnsupportedWebhookEventType("unknown-event type")
return (subject, body)
@ -205,7 +205,7 @@ def handle_issue_payload(action: str, issue: Dict[str, Any], actor: Dict[str, An
body = ISSUE_IGNORED_MESSAGE_TEMPLATE.format(**context)
else:
raise UnsupportedWebhookEventType("Sentry", "unknown-issue-action type")
raise UnsupportedWebhookEventType("unknown-issue-action type")
return (subject, body)
@ -233,7 +233,7 @@ def api_sentry_webhook(request: HttpRequest, user_profile: UserProfile,
elif "issue" in data:
subject, body = handle_issue_payload(payload["action"], data["issue"], payload["actor"])
else:
raise UnsupportedWebhookEventType("Sentry", str(list(data.keys())))
raise UnsupportedWebhookEventType(str(list(data.keys())))
else:
subject, body = handle_deprecated_payload(payload)

View File

@ -191,7 +191,7 @@ def topic_and_body(payload: Dict[str, Any]) -> Tuple[str, str]:
raise NotImplementedEventType()
if body is None:
raise UnsupportedWebhookEventType('Stripe', event_type)
raise UnsupportedWebhookEventType(event_type)
return (topic, body)
def amount_string(amount: int, currency: str) -> str:

View File

@ -29,6 +29,6 @@ def api_transifex_webhook(
elif reviewed:
body = f"Resource {resource} fully reviewed."
else:
raise UnsupportedWebhookEventType('Transifex', 'Unknown Event Type')
raise UnsupportedWebhookEventType('Unknown Event Type')
check_send_webhook_message(request, user_profile, subject, body)
return json_success()

View File

@ -40,4 +40,4 @@ def get_subject_and_body(payload: Mapping[str, Any], action_type: str) -> Option
if action_type in SUPPORTED_BOARD_ACTIONS:
return process_board_action(payload, action_type)
raise UnsupportedWebhookEventType("Trello", action_type)
raise UnsupportedWebhookEventType(action_type)

View File

@ -39,7 +39,7 @@ def get_proper_action(payload: Mapping[str, Any], action_type: Optional[str]) ->
return None
elif data['old']['name']:
return CHANGE_NAME
raise UnsupportedWebhookEventType("Trello", action_type)
raise UnsupportedWebhookEventType(action_type)
return action_type
def get_subject(payload: Mapping[str, Any]) -> str:

View File

@ -115,7 +115,7 @@ def get_proper_action(payload: Mapping[str, Any], action_type: str) -> Optional[
for field in ignored_fields:
if old_data.get(field):
return None
raise UnsupportedWebhookEventType("Trello", action_type)
raise UnsupportedWebhookEventType(action_type)
return action_type

View File

@ -75,4 +75,4 @@ def get_event_type(event: Dict[str, Any]) -> str:
event_type = event_type_match.group(1)
if event_type in EVENT_TYPE_BODY_MAPPER:
return event_type
raise UnsupportedWebhookEventType('Updown', event['event'])
raise UnsupportedWebhookEventType(event['event'])