This repository has been archived on 2026-03-24. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
people/src/backend/core/utils/webhooks.py
Marie PUPO JEAMMET cc39ed5298 (teams) add matrix webhook for teams
A webhook to invite/kick team members to a matrix room.
2025-06-21 00:15:16 +02:00

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