94 lines
2.9 KiB
Python
94 lines
2.9 KiB
Python
"""Fire webhooks with synchronous retries"""
|
|
|
|
import logging
|
|
|
|
import requests
|
|
|
|
from core import enums
|
|
from core.enums import WebhookStatusChoices
|
|
|
|
from .matrix import MatrixAPIClient
|
|
from .scim import SCIMClient
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class WebhookClient:
|
|
"""Wraps the SCIM client to record call results on webhooks."""
|
|
|
|
def __getattr__(self, name):
|
|
"""Handle calls from webhooks to synchronize a team access with a distant application."""
|
|
|
|
def wrapper(team, user):
|
|
"""
|
|
Wrap SCIMClient calls to handle retries, error handling and storing result in the
|
|
calling Webhook instance.
|
|
"""
|
|
for webhook in team.webhooks.all():
|
|
if not webhook.url:
|
|
continue
|
|
|
|
status = WebhookStatusChoices.FAILURE
|
|
response, webhook_succeeded = self._get_response_and_status(
|
|
name, webhook, user
|
|
)
|
|
|
|
if response is not None:
|
|
extra = {"response": response.content}
|
|
# pylint: disable=no-member
|
|
if webhook_succeeded:
|
|
logger.info(
|
|
"%s synchronization succeeded with %s",
|
|
name,
|
|
webhook.url,
|
|
extra=extra,
|
|
)
|
|
|
|
status = WebhookStatusChoices.SUCCESS
|
|
else:
|
|
logger.error(
|
|
"%s synchronization failed with %s",
|
|
name,
|
|
webhook.url,
|
|
extra=extra,
|
|
)
|
|
|
|
webhook._meta.model.objects.filter(id=webhook.id).update(status=status) # noqa
|
|
|
|
return wrapper
|
|
|
|
def _get_client(self, webhook):
|
|
"""Get client depending on the protocol."""
|
|
if webhook.protocol == enums.WebhookProtocolChoices.MATRIX:
|
|
return MatrixAPIClient()
|
|
|
|
return SCIMClient()
|
|
|
|
def _get_response_and_status(self, name, webhook, user):
|
|
"""Get response from webhook outside party."""
|
|
client = self._get_client(webhook)
|
|
|
|
try:
|
|
response, webhook_succeeded = getattr(client, name)(webhook, user)
|
|
except requests.exceptions.RetryError as exc:
|
|
logger.error(
|
|
"%s synchronization failed due to max retries exceeded with url %s",
|
|
name,
|
|
webhook.url,
|
|
exc_info=exc,
|
|
)
|
|
except requests.exceptions.RequestException as exc:
|
|
logger.error(
|
|
"%s synchronization failed with %s.",
|
|
name,
|
|
webhook.url,
|
|
exc_info=exc,
|
|
)
|
|
else:
|
|
return response, webhook_succeeded
|
|
|
|
return None, False
|
|
|
|
|
|
webhooks_synchronizer = WebhookClient()
|