diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b27a8df31ed770979b53ea8297778fd3ab00735..820478f2d1e188117023995f93e0d37b3f973d1e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,10 @@ Versioning](https://semver.org/spec/v2.0.0.html). - Allow lowercase server names only #11 +### Added + +- Kick Matrix ID from cancelled orders #9 + ## [1.3.0] - 2022-04-19 ### Added diff --git a/pretix_matrix_inviter/signals.py b/pretix_matrix_inviter/signals.py index fef84e1a7d3569048f6ca3c5e5ee7e3d6afdd323..1c46966cef06187b5b70385d89dd593b52486504 100644 --- a/pretix_matrix_inviter/signals.py +++ b/pretix_matrix_inviter/signals.py @@ -5,12 +5,18 @@ from django.urls import resolve, reverse from django.utils.translation import gettext_noop, ugettext_lazy as _ from i18nfield.strings import LazyI18nString from pretix.base.settings import settings_hierarkey -from pretix.base.signals import logentry_display, order_modified, order_placed +from pretix.base.signals import ( + logentry_display, + order_canceled, + order_expired, + order_modified, + order_placed, +) from pretix.base.templatetags.rich_text import rich_text_snippet from pretix.control.signals import nav_event_settings from pretix.presale.signals import question_form_fields -from .tasks import matrix_inviter_invite +from .tasks import matrix_inviter_invite, matrix_inviter_kick settings_hierarkey.add_default("matrix_inviter_items", [], list) settings_hierarkey.add_default("matrix_inviter_authorization_token", "", str) @@ -87,6 +93,36 @@ def matrix_inviter_invite_async(sender, order, **kwargs): ) +@receiver(order_canceled, dispatch_uid="matrix_inviter_order_canceled") +@receiver(order_expired, dispatch_uid="matrix_inviter_order_expired") +def matrix_inviter_kick_async(sender, order, **kwargs): + if ( + not sender.settings.matrix_inviter_authorization_token + and not sender.settings.matrix_inviter_matrix_server + and not sender.settings.matrix_inviter_matrix_room + ): + return + + for order_position in order.positions.all(): + if str(order_position.item.pk) not in sender.settings.get( + "matrix_inviter_items" + ): + continue + + if not order_position.meta_info_data.get("question_form_data", {}).get( + "matrix_inviter_matrix_id" + ): + continue + + matrix_inviter_kick.apply_async( + args=( + sender.pk, + order.pk, + order_position.pk, + ) + ) + + @receiver(nav_event_settings, dispatch_uid="matrix_inviter_nav_settings") def navbar_settings(sender, request=None, **kwargs): url = resolve(request.path_info) @@ -115,9 +151,15 @@ def logentry_display(sender, logentry, **kwargs): "pretix_matrix_inviter.invite_sent": _( "{matrix_id} has been invited to {matrix_room}." ), + "pretix_matrix_inviter.invite_rescinded": _( + "{matrix_id} has been removed from {matrix_room}." + ), "pretix_matrix_inviter.error": _( "There was an error inviting {matrix_id} to {matrix_room}: {error}" ), + "pretix_matrix_inviter.remove_error": _( + "There was an error removing {matrix_id} from {matrix_room}: {error}" + ), } data = json.loads(logentry.data) diff --git a/pretix_matrix_inviter/tasks.py b/pretix_matrix_inviter/tasks.py index c7cc984c741a48b0d95483713f50a33545e4f4c5..38925e98b4fd1e98726f1e2c62405de71c6818aa 100644 --- a/pretix_matrix_inviter/tasks.py +++ b/pretix_matrix_inviter/tasks.py @@ -87,3 +87,77 @@ def matrix_inviter_invite( "matrix_room": room_id, }, ) + + +@app.task( + base=ProfiledEventTask, + bind=True, + max_retries=10, + retry_backoff=True, + retry_backoff_max=3600, +) +def matrix_inviter_kick(self, event: int, order: int, order_position: int): + order_position = OrderPosition.objects.get(pk=order_position) + + user_matrix_id = order_position.meta_info_data.get("question_form_data", {}).get( + "matrix_inviter_matrix_id" + ) + + if not user_matrix_id: + return + + order = Order.objects.get(pk=order) + server = event.settings.matrix_inviter_matrix_server + token = event.settings.matrix_inviter_authorization_token + room_id = matrix_room_id(server, event.settings.matrix_inviter_matrix_room) + payload = {"user_id": user_matrix_id} + + try: + r = requests.post( + "https://{}/_matrix/client/v3/rooms/{}/kick".format( + url_quote(server), + url_quote(room_id), + ), + headers={ + "Authorization": "Bearer {}".format(token), + }, + json=payload, + ) + r.raise_for_status() + except (requests.ConnectionError, requests.HTTPError) as e: + if r.status_code in (403): + order.log_action( + "pretix_matrix_inviter.remove_error", + data={ + "matrix_id": user_matrix_id, + "matrix_room": room_id, + "error": "HTTP Code {} ({})".format( + r.status_code, r.json()["error"] + ), + }, + ) + else: + try: + if r.status_code == 429: + backoff = r.json()["retry_after_ms"] / 1000 + self.retry(countdown=backoff) + else: + self.retry() + except MaxRetriesExceededError: + order.log_action( + "pretix_matrix_inviter.remove_error", + data={ + "matrix_id": user_matrix_id, + "matrix_room": room_id, + "error": "HTTP Code {}".format(r.status_code), + }, + ) + raise e + else: + order.log_action( + "pretix_matrix_inviter.invite_rescinded", + data={ + "matrix_id": user_matrix_id, + "matrix_room": room_id, + }, + )