mirror of
https://github.com/jazzband/django-auditlog.git
synced 2026-03-16 22:20:26 +00:00
* Add CustomLogEntry model support and update tests: - Added support for CustomLogEntry data model to extend django-auditlog capabilities - Updated existing test cases to align with new model structure and data handling logic - Added new test cases to validate CustomLogEntry behavior, model registration, and signal handling - Ensured backward compatibility with existing LogEntry model where applicable * Update auditlog/__init__.py Co-authored-by: Youngkwang Yang <me@youngkwang.dev> * run only one custom model test matrix (#761) --------- Co-authored-by: Youngkwang Yang <me@youngkwang.dev>
198 lines
6 KiB
Python
198 lines
6 KiB
Python
from functools import wraps
|
|
|
|
from django.conf import settings
|
|
|
|
from auditlog import get_logentry_model
|
|
from auditlog.context import auditlog_disabled
|
|
from auditlog.diff import model_instance_diff
|
|
from auditlog.models import _get_manager_from_settings
|
|
from auditlog.signals import post_log, pre_log
|
|
|
|
|
|
def check_disable(signal_handler):
|
|
"""
|
|
Decorator that passes along disabled in kwargs if any of the following is true:
|
|
- 'auditlog_disabled' from threadlocal is true
|
|
- raw = True and AUDITLOG_DISABLE_ON_RAW_SAVE is True
|
|
"""
|
|
|
|
@wraps(signal_handler)
|
|
def wrapper(*args, **kwargs):
|
|
try:
|
|
auditlog_disabled_value = auditlog_disabled.get()
|
|
except LookupError:
|
|
auditlog_disabled_value = False
|
|
if not auditlog_disabled_value and not (
|
|
kwargs.get("raw") and settings.AUDITLOG_DISABLE_ON_RAW_SAVE
|
|
):
|
|
signal_handler(*args, **kwargs)
|
|
|
|
return wrapper
|
|
|
|
|
|
@check_disable
|
|
def log_create(sender, instance, created, **kwargs):
|
|
"""
|
|
Signal receiver that creates a log entry when a model instance is first saved to the database.
|
|
|
|
Direct use is discouraged, connect your model through :py:func:`auditlog.registry.register` instead.
|
|
"""
|
|
if created:
|
|
_create_log_entry(
|
|
action=get_logentry_model().Action.CREATE,
|
|
instance=instance,
|
|
sender=sender,
|
|
diff_old=None,
|
|
diff_new=instance,
|
|
use_json_for_changes=settings.AUDITLOG_STORE_JSON_CHANGES,
|
|
)
|
|
|
|
|
|
@check_disable
|
|
def log_update(sender, instance, **kwargs):
|
|
"""
|
|
Signal receiver that creates a log entry when a model instance is changed and saved to the database.
|
|
|
|
Direct use is discouraged, connect your model through :py:func:`auditlog.registry.register` instead.
|
|
"""
|
|
if not instance._state.adding and instance.pk is not None:
|
|
update_fields = kwargs.get("update_fields", None)
|
|
old = _get_manager_from_settings(sender).filter(pk=instance.pk).first()
|
|
_create_log_entry(
|
|
action=get_logentry_model().Action.UPDATE,
|
|
instance=instance,
|
|
sender=sender,
|
|
diff_old=old,
|
|
diff_new=instance,
|
|
fields_to_check=update_fields,
|
|
use_json_for_changes=settings.AUDITLOG_STORE_JSON_CHANGES,
|
|
)
|
|
|
|
|
|
@check_disable
|
|
def log_delete(sender, instance, **kwargs):
|
|
"""
|
|
Signal receiver that creates a log entry when a model instance is deleted from the database.
|
|
|
|
Direct use is discouraged, connect your model through :py:func:`auditlog.registry.register` instead.
|
|
"""
|
|
if instance.pk is not None:
|
|
_create_log_entry(
|
|
action=get_logentry_model().Action.DELETE,
|
|
instance=instance,
|
|
sender=sender,
|
|
diff_old=instance,
|
|
diff_new=None,
|
|
use_json_for_changes=settings.AUDITLOG_STORE_JSON_CHANGES,
|
|
)
|
|
|
|
|
|
def log_access(sender, instance, **kwargs):
|
|
"""
|
|
Signal receiver that creates a log entry when a model instance is accessed in a AccessLogDetailView.
|
|
|
|
Direct use is discouraged, connect your model through :py:func:`auditlog.registry.register` instead.
|
|
"""
|
|
if instance.pk is not None:
|
|
_create_log_entry(
|
|
action=get_logentry_model().Action.ACCESS,
|
|
instance=instance,
|
|
sender=sender,
|
|
diff_old=None,
|
|
diff_new=None,
|
|
force_log=True,
|
|
use_json_for_changes=settings.AUDITLOG_STORE_JSON_CHANGES,
|
|
)
|
|
|
|
|
|
def _create_log_entry(
|
|
action,
|
|
instance,
|
|
sender,
|
|
diff_old,
|
|
diff_new,
|
|
fields_to_check=None,
|
|
force_log=False,
|
|
use_json_for_changes=False,
|
|
):
|
|
pre_log_results = pre_log.send(
|
|
sender,
|
|
instance=instance,
|
|
action=action,
|
|
)
|
|
|
|
if any(item[1] is False for item in pre_log_results):
|
|
return
|
|
LogEntry = get_logentry_model()
|
|
|
|
error = None
|
|
log_entry = None
|
|
changes = None
|
|
try:
|
|
changes = model_instance_diff(
|
|
diff_old,
|
|
diff_new,
|
|
fields_to_check=fields_to_check,
|
|
use_json_for_changes=use_json_for_changes,
|
|
)
|
|
|
|
if force_log or changes:
|
|
log_entry = LogEntry.objects.log_create(
|
|
instance,
|
|
action=action,
|
|
changes=changes,
|
|
force_log=force_log,
|
|
)
|
|
except BaseException as e:
|
|
error = e
|
|
finally:
|
|
if log_entry or error:
|
|
post_log.send(
|
|
sender,
|
|
instance=instance,
|
|
instance_old=diff_old,
|
|
action=action,
|
|
error=error,
|
|
pre_log_results=pre_log_results,
|
|
changes=changes,
|
|
log_entry=log_entry,
|
|
log_created=log_entry is not None,
|
|
use_json_for_changes=settings.AUDITLOG_STORE_JSON_CHANGES,
|
|
)
|
|
if error:
|
|
raise error
|
|
|
|
|
|
def make_log_m2m_changes(field_name):
|
|
"""Return a handler for m2m_changed with field_name enclosed."""
|
|
|
|
@check_disable
|
|
def log_m2m_changes(signal, action, **kwargs):
|
|
"""Handle m2m_changed and call LogEntry.objects.log_m2m_changes as needed."""
|
|
if action not in ["post_add", "post_clear", "post_remove"]:
|
|
return
|
|
LogEntry = get_logentry_model()
|
|
|
|
model_manager = _get_manager_from_settings(kwargs["model"])
|
|
|
|
if action == "post_clear":
|
|
changed_queryset = model_manager.all()
|
|
else:
|
|
changed_queryset = model_manager.filter(pk__in=kwargs["pk_set"])
|
|
|
|
if action in ["post_add"]:
|
|
LogEntry.objects.log_m2m_changes(
|
|
changed_queryset,
|
|
kwargs["instance"],
|
|
"add",
|
|
field_name,
|
|
)
|
|
elif action in ["post_remove", "post_clear"]:
|
|
LogEntry.objects.log_m2m_changes(
|
|
changed_queryset,
|
|
kwargs["instance"],
|
|
"delete",
|
|
field_name,
|
|
)
|
|
|
|
return log_m2m_changes
|