diff --git a/src/pretix/api/webhooks.py b/src/pretix/api/webhooks.py index 45190fc117..c070eaf47e 100644 --- a/src/pretix/api/webhooks.py +++ b/src/pretix/api/webhooks.py @@ -384,7 +384,7 @@ def register_default_webhook_events(sender, **kwargs): def notify_webhooks(logentry_ids: list): if not isinstance(logentry_ids, list): logentry_ids = [logentry_ids] - qs = LogEntry.all.select_related('event', 'event__organizer').filter(id__in=logentry_ids) + qs = LogEntry.all.select_related('event', 'event__organizer', 'organizer_link').filter(id__in=logentry_ids) _org, _at, webhooks = None, None, None for logentry in qs: if not logentry.organizer: diff --git a/src/pretix/base/migrations/0252_logentry_organizer.py b/src/pretix/base/migrations/0252_logentry_organizer.py new file mode 100644 index 0000000000..af86f5e196 --- /dev/null +++ b/src/pretix/base/migrations/0252_logentry_organizer.py @@ -0,0 +1,56 @@ +# Generated by Django 4.2.4 on 2023-11-20 12:38 + +import django.db.models.deletion +from django.db import migrations, models +from django.db.models import F, OuterRef, Subquery + + +def backfill_organizer(apps, schema_editor): + LogEntry = apps.get_model("pretixbase", "LogEntry") + Event = apps.get_model("pretixbase", "Event") + ContentType = apps.get_model("contenttypes", "ContentType") + + LogEntry.objects.filter( + organizer_link__isnull=True, event__isnull=False + ).update(organizer_link_id=Subquery( + Event.objects.filter(pk=OuterRef('event_id')).values('organizer_id'), + ) + ) + for ct in ContentType.objects.all(): + try: + model = apps.get_model(ct.app_label, ct.model) + except LookupError: + continue + if "organizer" in model._meta.fields: + LogEntry.objects.filter( + organizer_link__isnull=True, event__isnull=True, content_type=ct, + ).update( + organizer_link_id=Subquery(model.objects.filter(pk=OuterRef('object_id')).values('organizer_id')) + ) + elif "event" in model._meta.fields: + LogEntry.objects.filter( + organizer_link__isnull=True, event__isnull=True, content_type=ct, + ).update( + organizer_link_id=Subquery(model.objects.filter(pk=OuterRef('object_id')).values('event__organizer_id')) + ) + + +class Migration(migrations.Migration): + dependencies = [ + ("pretixbase", "0251_order_invoice_dirty"), + ] + + operations = [ + migrations.AddField( + model_name="logentry", + name="organizer_link", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.PROTECT, + to="pretixbase.organizer", + ), + ), + migrations.RunPython( + backfill_organizer, + ) + ] diff --git a/src/pretix/base/models/base.py b/src/pretix/base/models/base.py index 478ce13e64..cd754b1325 100644 --- a/src/pretix/base/models/base.py +++ b/src/pretix/base/models/base.py @@ -84,13 +84,21 @@ class LoggingMixin: from .devices import Device from .event import Event from .log import LogEntry - from .organizer import TeamAPIToken + from .organizer import Organizer, TeamAPIToken event = None - if isinstance(self, Event): + organizer_id = None + if isinstance(self, Organizer): + organizer_id = self.pk + elif isinstance(self, Event): event = self + organizer_id = self.organizer_id elif hasattr(self, 'event'): event = self.event + organizer_id = self.event.organizer_id + elif hasattr(self, 'organizer_id'): + organizer_id = self.organizer_id + if user and not user.is_authenticated: user = None @@ -106,7 +114,8 @@ class LoggingMixin: elif isinstance(api_token, TeamAPIToken): kwargs['api_token'] = api_token - logentry = LogEntry(content_object=self, user=user, action_type=action, event=event, **kwargs) + logentry = LogEntry(content_object=self, user=user, action_type=action, event=event, + organizer_link_id=organizer_id, **kwargs) if isinstance(data, dict): sensitivekeys = ['password', 'secret', 'api_key'] diff --git a/src/pretix/base/models/log.py b/src/pretix/base/models/log.py index 1a9d3ae31c..3f715a1246 100644 --- a/src/pretix/base/models/log.py +++ b/src/pretix/base/models/log.py @@ -78,6 +78,7 @@ class LogEntry(models.Model): device = models.ForeignKey('Device', null=True, blank=True, on_delete=models.PROTECT) oauth_application = models.ForeignKey('pretixapi.OAuthApplication', null=True, blank=True, on_delete=models.PROTECT) event = models.ForeignKey('Event', null=True, blank=True, on_delete=models.SET_NULL) + organizer_link = models.ForeignKey('Organizer', null=True, blank=True, on_delete=models.PROTECT) action_type = models.CharField(max_length=255) data = models.TextField(default='{}') visible = models.BooleanField(default=True) @@ -126,7 +127,9 @@ class LogEntry(models.Model): def organizer(self): from .organizer import Organizer - if self.event: + if self.organizer_link: + return self.organizer_link + elif self.event: return self.event.organizer elif hasattr(self.content_object, 'event'): return self.content_object.event.organizer