class
LogMixin
pretalx.common.models.mixins.LogMixin source
Adds logging utilities for integrating pretalx.common.models.ActivityLog.
Attributes 2
log_parentNonelog_prefixNoneMethods 4
Defined here
delete(*args, log_kwargs=None, skip_log=False, **kwargs)source
def delete(self, *args, log_kwargs=None, skip_log=False, **kwargs):
parent = self.log_parent
result = super().delete(*args, **kwargs)
if (
not skip_log
and parent
and getattr(parent, "log_action", None)
and self.log_prefix
):
log_kwargs = log_kwargs or {}
parent.log_action(f"{self.log_prefix}.delete", **log_kwargs)
return result
get_instance_data()sourceGet a dictionary of field values for this instance.
Used for change tracking in log_action. Excludes auto-updated fields like timestamps and sensitive data. Does not handle many-to-many fields.
def get_instance_data(self):
"""Get a dictionary of field values for this instance.
Used for change tracking in log_action. Excludes auto-updated
fields like timestamps and sensitive data.
Does not handle many-to-many fields.
"""
excluded_fields = {
"created",
"updated",
"is_active",
"last_login",
"user",
"event",
"code",
}
data = {}
for field in self._meta.fields:
if (
field.name in excluded_fields
or field.name in SENSITIVE_KEYS
or "thumbnail" in field.name
or getattr(field, "auto_now", False)
or getattr(field, "auto_now_add", False)
):
continue
if isinstance(field, models.ForeignKey):
data[field.name] = getattr(self, field.attname, None)
continue
value = getattr(self, field.name, None)
if isinstance(field, models.FileField):
data[field.name] = value.name if value else None
elif isinstance(field, models.UUIDField):
data[field.name] = str(value) if value else None
elif isinstance(value, LazyI18nString):
if isinstance(getattr(value, "data", None), dict):
data[field.name] = {k: v for k, v in value.data.items() if v}
else:
data[field.name] = str(value)
else:
data[field.name] = json_roundtrip(value)
return data
log_action(action, data=None, person=None, orga=False, content_object=None, old_data=None, new_data=None)source
def log_action(
self,
action,
data=None,
person=None,
orga=False,
content_object=None,
old_data=None,
new_data=None,
):
if self._state.adding or not isinstance(self.pk, int):
return
if action.startswith("."):
if self.log_prefix:
action = f"{self.log_prefix}{action}"
else:
return
if old_data is not None or new_data is not None:
from pretalx.common.log import ( # noqa: PLC0415 -- thin method
compute_log_changes,
)
changes = compute_log_changes(old_data, new_data)
if not changes and not data:
return
if changes:
if data is None:
data = {}
data["changes"] = changes
if data:
if not isinstance(data, dict):
raise TypeError(
f"Logged data should always be a dictionary, not {type(data)}."
)
for key in data:
if any(sensitive_key in key for sensitive_key in SENSITIVE_KEYS):
data[key] = "********" if data[key] else data[key]
data = json_roundtrip(data)
return ActivityLog.objects.create(
person=person,
content_object=content_object or self,
action_type=action,
data=data,
is_orga_action=orga,
**self._log_event_kwargs(),
)
logged_actions()source
def logged_actions(self):
return (
ActivityLog.objects.filter(
content_type=ContentType.objects.get_for_model(type(self)),
object_id=self.pk,
)
.select_related("event", "person")
.prefetch_related("content_object")
)