mirror of
https://github.com/pretix/pretix.git
synced 2025-12-05 21:32:28 +00:00
Compare commits
1 Commits
fix-csv-er
...
notificati
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
82e4c331fc |
@@ -22,6 +22,7 @@
|
||||
from datetime import timedelta
|
||||
|
||||
from django.db import models
|
||||
from django.db.models import Exists, OuterRef, Q
|
||||
from django.urls import reverse
|
||||
from django.utils.timezone import now
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
@@ -111,6 +112,24 @@ class OAuthRefreshToken(AbstractRefreshToken):
|
||||
)
|
||||
|
||||
|
||||
class WebHookQuerySet(models.QuerySet):
|
||||
def for_notification(self, action_type, organizer, event):
|
||||
event_listener = WebHookEventListener.objects.filter(
|
||||
webhook=OuterRef('pk'),
|
||||
action_type=action_type
|
||||
)
|
||||
webhooks = WebHook.objects.annotate(has_el=Exists(event_listener)).filter(
|
||||
organizer=organizer,
|
||||
has_el=True,
|
||||
enabled=True
|
||||
)
|
||||
if event:
|
||||
webhooks = webhooks.filter(
|
||||
Q(all_events=True) | Q(limit_events__pk=event.pk if not isinstance(event, int) else event)
|
||||
)
|
||||
return webhooks
|
||||
|
||||
|
||||
class WebHook(models.Model):
|
||||
organizer = models.ForeignKey('pretixbase.Organizer', on_delete=models.CASCADE, related_name='webhooks')
|
||||
enabled = models.BooleanField(default=True, verbose_name=_("Enable webhook"))
|
||||
@@ -119,6 +138,8 @@ class WebHook(models.Model):
|
||||
limit_events = models.ManyToManyField('pretixbase.Event', verbose_name=_("Limit to events"), blank=True)
|
||||
comment = models.CharField(verbose_name=_("Comment"), max_length=255, null=True, blank=True)
|
||||
|
||||
objects = models.Manager.from_queryset(WebHookQuerySet)()
|
||||
|
||||
class Meta:
|
||||
ordering = ('id',)
|
||||
|
||||
|
||||
@@ -27,16 +27,13 @@ from datetime import timedelta
|
||||
|
||||
import requests
|
||||
from django.db import DatabaseError, connection, transaction
|
||||
from django.db.models import Exists, OuterRef, Q
|
||||
from django.dispatch import receiver
|
||||
from django.utils.timezone import now
|
||||
from django.utils.translation import gettext_lazy as _, pgettext_lazy
|
||||
from django_scopes import scope, scopes_disabled
|
||||
from requests import RequestException
|
||||
|
||||
from pretix.api.models import (
|
||||
WebHook, WebHookCall, WebHookCallRetry, WebHookEventListener,
|
||||
)
|
||||
from pretix.api.models import WebHook, WebHookCall, WebHookCallRetry
|
||||
from pretix.api.signals import register_webhook_events
|
||||
from pretix.base.models import LogEntry
|
||||
from pretix.base.services.tasks import ProfiledTask, TransactionAwareTask
|
||||
@@ -454,20 +451,9 @@ def notify_webhooks(logentry_ids: list):
|
||||
_org = logentry.organizer
|
||||
_at = logentry.action_type
|
||||
|
||||
# All webhooks that registered for this notification
|
||||
event_listener = WebHookEventListener.objects.filter(
|
||||
webhook=OuterRef('pk'),
|
||||
action_type=notification_type.action_type
|
||||
webhooks = WebHook.objects.for_notification(
|
||||
notification_type.action_type, logentry.organizer, logentry.event_id
|
||||
)
|
||||
webhooks = WebHook.objects.annotate(has_el=Exists(event_listener)).filter(
|
||||
organizer=logentry.organizer,
|
||||
has_el=True,
|
||||
enabled=True
|
||||
)
|
||||
if logentry.event_id:
|
||||
webhooks = webhooks.filter(
|
||||
Q(all_events=True) | Q(limit_events__pk=logentry.event_id)
|
||||
)
|
||||
|
||||
for wh in webhooks:
|
||||
send_webhook.apply_async(args=(logentry.id, notification_type.action_type, wh.pk))
|
||||
|
||||
@@ -38,8 +38,11 @@ import logging
|
||||
from django.contrib.contenttypes.fields import GenericForeignKey
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.db import connections, models
|
||||
from django.db.models import Q
|
||||
from django.utils.functional import cached_property
|
||||
|
||||
from pretix.api.models import WebHook
|
||||
|
||||
|
||||
class VisibleOnlyManager(models.Manager):
|
||||
def get_queryset(self):
|
||||
@@ -181,12 +184,56 @@ class LogEntry(models.Model):
|
||||
@classmethod
|
||||
def bulk_postprocess(cls, objects):
|
||||
from pretix.api.webhooks import notify_webhooks
|
||||
from pretix.base.models import NotificationSetting
|
||||
|
||||
from ..services.notifications import notify
|
||||
|
||||
to_notify = [o.id for o in objects if o.notification_type]
|
||||
# Regular LogEntry.save() always kicks off notify and notify_webhooks tasks, regardless of whether a webhook
|
||||
# listener exists. However, in bulk processing, it makes sense to check once and then only create the task if
|
||||
# there is something to do.
|
||||
_webhook_active_cache = {}
|
||||
_notification_active_cache = {}
|
||||
|
||||
def _is_webhook_active(logentry):
|
||||
nonlocal _webhook_active_cache
|
||||
|
||||
key = (logentry.action_type, logentry.organizer_id, logentry.event_id)
|
||||
if key not in _webhook_active_cache:
|
||||
notification_type = logentry.webhook_type
|
||||
_webhook_active_cache[key] = notification_type and WebHook.objects.for_notification(
|
||||
notification_type.action_type, logentry.organizer, logentry.event_id
|
||||
).exists()
|
||||
return _webhook_active_cache[key]
|
||||
|
||||
def _is_notification_active(logentry):
|
||||
nonlocal _notification_active_cache
|
||||
|
||||
key = (logentry.action_type, logentry.organizer_id, logentry.event_id)
|
||||
if key not in _notification_active_cache:
|
||||
notification_type = logentry.notification_type
|
||||
if notification_type and logentry.event:
|
||||
# We only have event-related notifications right now
|
||||
users = logentry.event.get_users_with_permission(
|
||||
notification_type.required_permission
|
||||
).filter(notifications_send=True, is_active=True)
|
||||
|
||||
_notification_active_cache[key] = NotificationSetting.objects.filter(
|
||||
# This is not technically fully correct since it's returning True if a user has the
|
||||
# notification enabled on the global level and then disabled on the per-event-level,
|
||||
# but it's good enough as a first check to avoid useless celery tasks for bulk actions
|
||||
Q(event_id=logentry.event_id) | Q(event__isnull=True),
|
||||
action_type=notification_type.action_type,
|
||||
user__pk__in=users.values_list('pk', flat=True),
|
||||
enabled=True,
|
||||
).exists()
|
||||
|
||||
else:
|
||||
_webhook_active_cache[key] = False
|
||||
return _notification_active_cache[key]
|
||||
|
||||
to_notify = [o.id for o in objects if _is_notification_active(o)]
|
||||
if to_notify:
|
||||
notify.apply_async(args=(to_notify,))
|
||||
to_wh = [o.id for o in objects if o.webhook_type]
|
||||
to_wh = [o.id for o in objects if _is_webhook_active(o)]
|
||||
if to_wh:
|
||||
notify_webhooks.apply_async(args=(to_wh,))
|
||||
|
||||
Reference in New Issue
Block a user