diff --git a/apps/api/__init__.py b/apps/api/__init__.py new file mode 100644 index 00000000..1b17aec6 --- /dev/null +++ b/apps/api/__init__.py @@ -0,0 +1,4 @@ +# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay +# SPDX-License-Identifier: GPL-3.0-or-later + +default_app_config = 'api.apps.APIConfig' diff --git a/apps/api/apps.py b/apps/api/apps.py new file mode 100644 index 00000000..11d78652 --- /dev/null +++ b/apps/api/apps.py @@ -0,0 +1,10 @@ +# 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 APIConfig(AppConfig): + name = 'api' + verbose_name = _('API') diff --git a/apps/logs/__init__.py b/apps/logs/__init__.py new file mode 100644 index 00000000..58ee5b08 --- /dev/null +++ b/apps/logs/__init__.py @@ -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' diff --git a/apps/logs/apps.py b/apps/logs/apps.py new file mode 100644 index 00000000..f48820c7 --- /dev/null +++ b/apps/logs/apps.py @@ -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 diff --git a/apps/logs/models.py b/apps/logs/models.py new file mode 100644 index 00000000..17e8c710 --- /dev/null +++ b/apps/logs/models.py @@ -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.")) diff --git a/apps/logs/signals.py b/apps/logs/signals.py new file mode 100644 index 00000000..646739fa --- /dev/null +++ b/apps/logs/signals.py @@ -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() diff --git a/apps/logs/urls.py b/apps/logs/urls.py new file mode 100644 index 00000000..6d76674c --- /dev/null +++ b/apps/logs/urls.py @@ -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 = [ +] diff --git a/locale/de/LC_MESSAGES/django.po b/locale/de/LC_MESSAGES/django.po index 3aadf83e..618447da 100644 --- a/locale/de/LC_MESSAGES/django.po +++ b/locale/de/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-02-21 13:50+0100\n" +"POT-Creation-Date: 2020-02-24 17:15+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -82,6 +82,46 @@ msgstr "" msgid "guests" msgstr "" +#: apps/api/apps.py:10 +msgid "API" +msgstr "" + +#: apps/logs/apps.py:10 +msgid "Logs" +msgstr "" + +#: apps/logs/models.py:20 apps/note/models/notes.py:105 +msgid "user" +msgstr "" + +#: apps/logs/models.py:27 +msgid "model" +msgstr "" + +#: apps/logs/models.py:34 +msgid "identifier" +msgstr "" + +#: apps/logs/models.py:39 +msgid "previous data" +msgstr "" + +#: apps/logs/models.py:44 +msgid "new data" +msgstr "" + +#: apps/logs/models.py:51 +msgid "action" +msgstr "" + +#: apps/logs/models.py:59 +msgid "timestamp" +msgstr "" + +#: apps/logs/models.py:63 +msgid "Logs cannot be destroyed." +msgstr "" + #: apps/member/apps.py:10 msgid "member" msgstr "" @@ -244,10 +284,6 @@ msgstr "" msgid "This alias is already taken." msgstr "" -#: apps/note/models/notes.py:105 -msgid "user" -msgstr "" - #: apps/note/models/notes.py:109 msgid "one's note" msgstr "" @@ -358,15 +394,19 @@ msgstr "" msgid "Transfer money from your account to one or others" msgstr "" -#: note_kfet/settings/base.py:148 -msgid "German" -msgstr "" - -#: note_kfet/settings/base.py:149 -msgid "English" +#: apps/note/views.py:143 +msgid "Consommations" msgstr "" #: note_kfet/settings/base.py:150 +msgid "German" +msgstr "" + +#: note_kfet/settings/base.py:151 +msgid "English" +msgstr "" + +#: note_kfet/settings/base.py:152 msgid "French" msgstr "" diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po index bdf4fc8f..fdb98479 100644 --- a/locale/fr/LC_MESSAGES/django.po +++ b/locale/fr/LC_MESSAGES/django.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-02-21 13:50+0100\n" +"POT-Creation-Date: 2020-02-24 17:15+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -77,6 +77,50 @@ msgstr "invité" msgid "guests" msgstr "invités" +#: apps/api/apps.py:10 +msgid "API" +msgstr "" + +#: apps/logs/apps.py:10 +msgid "Logs" +msgstr "" + +#: apps/logs/models.py:20 apps/note/models/notes.py:105 +msgid "user" +msgstr "utilisateur" + +#: apps/logs/models.py:27 +msgid "model" +msgstr "Modèle" + +#: apps/logs/models.py:34 +msgid "identifier" +msgstr "Identifiant" + +#: apps/logs/models.py:39 +msgid "previous data" +msgstr "Données précédentes" + +#: apps/logs/models.py:44 +#, fuzzy +#| msgid "end date" +msgid "new data" +msgstr "Nouvelles données" + +#: apps/logs/models.py:51 +#, fuzzy +#| msgid "section" +msgid "action" +msgstr "Action" + +#: apps/logs/models.py:59 +msgid "timestamp" +msgstr "Date" + +#: apps/logs/models.py:63 +msgid "Logs cannot be destroyed." +msgstr "Les logs ne peuvent pas être détruits." + #: apps/member/apps.py:10 msgid "member" msgstr "adhérent" @@ -244,10 +288,6 @@ msgstr "Note" msgid "This alias is already taken." msgstr "Cet alias est déjà pris." -#: apps/note/models/notes.py:105 -msgid "user" -msgstr "utilisateur" - #: apps/note/models/notes.py:109 msgid "one's note" msgstr "note d'un utilisateur" @@ -358,15 +398,21 @@ msgstr "transactions d'adhésion" msgid "Transfer money from your account to one or others" msgstr "Transfert d'argent de ton compte vers un ou plusieurs autres" -#: note_kfet/settings/base.py:148 +#: apps/note/views.py:143 +#, fuzzy +#| msgid "transactions" +msgid "Consommations" +msgstr "transactions" + +#: note_kfet/settings/base.py:150 msgid "German" msgstr "" -#: note_kfet/settings/base.py:149 +#: note_kfet/settings/base.py:151 msgid "English" msgstr "" -#: note_kfet/settings/base.py:150 +#: note_kfet/settings/base.py:152 msgid "French" msgstr "" diff --git a/note_kfet/settings/base.py b/note_kfet/settings/base.py index ab4453e4..eb0787cd 100644 --- a/note_kfet/settings/base.py +++ b/note_kfet/settings/base.py @@ -61,6 +61,7 @@ INSTALLED_APPS = [ 'member', 'note', 'api', + 'logs', ] LOGIN_REDIRECT_URL = '/note/transfer/' diff --git a/note_kfet/urls.py b/note_kfet/urls.py index 303e229a..fe87cc05 100644 --- a/note_kfet/urls.py +++ b/note_kfet/urls.py @@ -21,4 +21,6 @@ urlpatterns = [ # Include Django REST API path('api/', include('api.urls')), + + path('logs/', include('logs.urls')), ]