mirror of
https://github.com/jazzband/django-auditlog.git
synced 2026-03-16 22:20:26 +00:00
* Update receivers.py * Update signals.py * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Update signals.py Removed trailing whitespace... * Update tests.py * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Update CHANGELOG.md * Update CHANGELOG.md --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Hasan Ramezani <hasan.r67@gmail.com>
178 lines
5.2 KiB
Python
178 lines
5.2 KiB
Python
from functools import wraps
|
|
|
|
from django.conf import settings
|
|
|
|
from auditlog.context import auditlog_disabled
|
|
from auditlog.diff import model_instance_diff
|
|
from auditlog.models import LogEntry
|
|
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=LogEntry.Action.CREATE,
|
|
instance=instance,
|
|
sender=sender,
|
|
diff_old=None,
|
|
diff_new=instance,
|
|
)
|
|
|
|
|
|
@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:
|
|
update_fields = kwargs.get("update_fields", None)
|
|
old = sender.objects.filter(pk=instance.pk).first()
|
|
_create_log_entry(
|
|
action=LogEntry.Action.UPDATE,
|
|
instance=instance,
|
|
sender=sender,
|
|
diff_old=old,
|
|
diff_new=instance,
|
|
fields_to_check=update_fields,
|
|
)
|
|
|
|
|
|
@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=LogEntry.Action.DELETE,
|
|
instance=instance,
|
|
sender=sender,
|
|
diff_old=instance,
|
|
diff_new=None,
|
|
)
|
|
|
|
|
|
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=LogEntry.Action.ACCESS,
|
|
instance=instance,
|
|
sender=sender,
|
|
diff_old=None,
|
|
diff_new=None,
|
|
force_log=True,
|
|
)
|
|
|
|
|
|
def _create_log_entry(
|
|
action, instance, sender, diff_old, diff_new, fields_to_check=None, force_log=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
|
|
|
|
error = None
|
|
log_created = False
|
|
changes = None
|
|
try:
|
|
changes = model_instance_diff(
|
|
diff_old, diff_new, fields_to_check=fields_to_check
|
|
)
|
|
|
|
if force_log or changes:
|
|
LogEntry.objects.log_create(
|
|
instance,
|
|
action=action,
|
|
changes=changes,
|
|
force_log=force_log,
|
|
)
|
|
log_created = True
|
|
except BaseException as e:
|
|
error = e
|
|
finally:
|
|
if log_created 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_created=log_created,
|
|
)
|
|
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
|
|
|
|
if action == "post_clear":
|
|
changed_queryset = kwargs["model"].objects.all()
|
|
else:
|
|
changed_queryset = kwargs["model"].objects.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
|