1
0
mirror of https://gitlab.crans.org/bde/nk20 synced 2025-06-21 01:48:21 +02:00

Logging support

This commit is contained in:
Yohann D'ANELLO
2020-02-24 18:18:44 +01:00
parent c8dd41c1d7
commit fd529a53c8
11 changed files with 279 additions and 19 deletions

4
apps/logs/__init__.py Normal file
View File

@ -0,0 +1,4 @@
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later
default_app_config = 'logs.apps.LogsConfig'

14
apps/logs/apps.py Normal file
View File

@ -0,0 +1,14 @@
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later
from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _
class LogsConfig(AppConfig):
name = 'logs'
verbose_name = _('Logs')
def ready(self):
# noinspection PyUnresolvedReferences
import logs.signals

63
apps/logs/models.py Normal file
View File

@ -0,0 +1,63 @@
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later
from django.utils.translation import gettext_lazy as _
from django.conf import settings
from django.core.exceptions import ValidationError
from django.db import models
class Changelog(models.Model):
"""
Store each modification on the database (except sessions and logging),
including creating, editing and deleting models.
"""
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.PROTECT,
null=True,
verbose_name=_('user'),
)
model = models.CharField(
max_length=255,
null=False,
blank=False,
verbose_name=_('model'),
)
instance_pk = models.CharField(
max_length=255,
null=False,
blank=False,
verbose_name=_('identifier'),
)
previous = models.TextField(
null=True,
verbose_name=_('previous data'),
)
data = models.TextField(
null=True,
verbose_name=_('new data'),
)
action = models.CharField( # create, edit or delete
max_length=16,
null=False,
blank=False,
verbose_name=_('action'),
)
timestamp = models.DateTimeField(
null=False,
blank=False,
auto_now_add=True,
name='timestamp',
verbose_name=_('timestamp'),
)
def delete(self, using=None, keep_parents=False):
raise ValidationError(_("Logs cannot be destroyed."))

68
apps/logs/signals.py Normal file
View File

@ -0,0 +1,68 @@
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later
import inspect
from django.core import serializers
from django.db.models.signals import pre_save, pre_delete
from django.dispatch import receiver
from .models import Changelog
def get_user_in_signal(sender, **kwargs):
user = None
for entry in reversed(inspect.stack()):
try:
user = entry[0].f_locals['request'].user
break
except:
pass
if not user:
print("WARNING: Attempt to save " + str(sender) + " with no user")
return user
EXCLUDED = [
'Changelog',
'Migration',
'Session',
]
@receiver(pre_save)
def save_object(sender, instance, **kwargs):
model_name = sender.__name__
if model_name in EXCLUDED:
return
previous = sender.objects.filter(pk=instance.pk).all()
user = get_user_in_signal(sender, **kwargs)
if previous.exists:
previous_json = serializers.serialize('json', previous)[1:-1]
else:
previous_json = None
instance_json = serializers.serialize('json', [instance, ],)[1:-1]
Changelog.objects.create(user=user,
model=model_name,
instance_pk=instance.pk,
previous=previous_json,
data=instance_json,
action=("edit" if previous.exists() else "create")
)#.save()
@receiver(pre_delete)
def delete_object(sender, instance, **kwargs):
model_name = sender.__name__
if model_name in EXCLUDED:
return
user = get_user_in_signal(sender, **kwargs)
instance_json = serializers.serialize('json', [instance, ])[1:-1]
Changelog.objects.create(user=user,
model=model_name,
instance_pk=instance.pk,
previous=instance_json,
data=None,
action="delete"
).save()

8
apps/logs/urls.py Normal file
View File

@ -0,0 +1,8 @@
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later
app_name = 'logs'
# TODO User interface
urlpatterns = [
]