Commit 50c2f816 authored by Sli's avatar Sli
Browse files

Merge branch 'deletion_logs' into 'master'

Add generic operation logs and implements it for Sellings and Refilling deletions

See merge request !259
parents 129f2e53 5c30de5f
Pipeline #2139 passed with stage
in 44 minutes and 32 seconds
......@@ -23,6 +23,7 @@
#
import importlib
import threading
from django.conf import settings
from django.utils.functional import SimpleLazyObject
from django.contrib.auth import get_user
......@@ -49,8 +50,31 @@ class AuthenticationMiddleware(DjangoAuthenticationMiddleware):
def process_request(self, request):
assert hasattr(request, "session"), (
"The Django authentication middleware requires session middleware "
"to be installed. Edit your MIDDLEWARE_CLASSES setting to insert "
"to be installed. Edit your MIDDLEWARE setting to insert "
"'django.contrib.sessions.middleware.SessionMiddleware' before "
"'account.middleware.AuthenticationMiddleware'."
)
request.user = SimpleLazyObject(lambda: get_cached_user(request))
_threadlocal = threading.local()
def get_signal_request():
"""
!!! Do not use if your operation is asynchronus !!!
Allow to access current request in signals
This is a hack that looks into the thread
Mainly used for log purpose
"""
return getattr(_threadlocal, "request", None)
class SignalRequestMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
setattr(_threadlocal, "request", request)
return self.get_response(request)
# Generated by Django 2.2.6 on 2019-11-14 15:10
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
("core", "0033_auto_20191006_0049"),
]
operations = [
migrations.CreateModel(
name="OperationLog",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("date", models.DateTimeField(auto_now_add=True, verbose_name="date")),
("label", models.CharField(max_length=255, verbose_name="label")),
(
"operation_type",
models.CharField(
choices=[
("SELLING_DELETION", "Selling deletion"),
("REFILLING_DELETION", "Refilling deletion"),
],
max_length=40,
verbose_name="operation type",
),
),
(
"operator",
models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="logs",
to=settings.AUTH_USER_MODEL,
),
),
],
),
]
......@@ -1454,3 +1454,24 @@ class Gift(models.Model):
def is_owned_by(self, user):
return user.is_board_member or user.is_root
class OperationLog(models.Model):
"""
General purpose log object to register operations
"""
date = models.DateTimeField(_("date"), auto_now_add=True)
label = models.CharField(_("label"), max_length=255)
operator = models.ForeignKey(
User, related_name="logs", on_delete=models.SET_NULL, null=True
)
operation_type = models.CharField(
_("operation type"), max_length=40, choices=settings.SITH_LOG_OPERATION_TYPE,
)
def is_owned_by(self, user):
return user.is_root
def __str__(self):
return "%s - %s - %s" % (self.operation_type, self.label, self.operator)
......@@ -63,7 +63,7 @@
<td>{{ i.amount }}</td>
<td>{{ i.get_payment_method_display() }}</td>
{% if i.is_owned_by(user) %}
<td><a href="{{ url('counter:refilling_delete', refilling_id=i.id) }}">Delete</a></td>
<td><a href="{{ url('counter:refilling_delete', refilling_id=i.id) }}">{% trans %}Delete{% endtrans %}</a></td>
{% endif %}
</tr>
{% endfor %}
......
......@@ -13,6 +13,7 @@
{% if user.is_root %}
<li><a href="{{ url('core:group_list') }}">{% trans %}Groups{% endtrans %}</a></li>
<li><a href="{{ url('rootplace:merge') }}">{% trans %}Merge users{% endtrans %}</a></li>
<li><a href="{{ url('rootplace:operation_logs') }}">{% trans %}Operation logs{% endtrans %}</a></li>
<li><a href="{{ url('rootplace:delete_forum_messages') }}">{% trans %}Delete user's forum messages{% endtrans %}</a></li>
{% endif %}
{% if user.can_create_subscription or user.is_root %}
......
# -*- coding:utf-8 -*
#
# Copyright 2016,2017
# Copyright 2016,2017,2019
# - Skia <skia@libskia.so>
# - Sli <antoine@bartuccio.fr>
#
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# http://ae.utbm.fr.
......@@ -21,3 +22,5 @@
# Place - Suite 330, Boston, MA 02111-1307, USA.
#
#
default_app_config = "counter.app.CounterConfig"
# -*- coding:utf-8 -*
#
# Copyright 2019
# - Sli <antoine@bartuccio.fr>
#
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# http://ae.utbm.fr.
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License a published by the Free Software
# Foundation; either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
# Place - Suite 330, Boston, MA 02111-1307, USA.
#
#
from django.apps import AppConfig
from django.utils.translation import ugettext_lazy as _
class CounterConfig(AppConfig):
name = "counter"
verbose_name = _("counter")
def ready(self):
import counter.signals
# -*- coding:utf-8 -*
#
# Copyright 2019
# - Sli <antoine@bartuccio.fr>
#
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# http://ae.utbm.fr.
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License a published by the Free Software
# Foundation; either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
# Place - Suite 330, Boston, MA 02111-1307, USA.
#
#
from django.db.models.signals import pre_delete
from django.dispatch import receiver
from django.conf import settings
from core.middleware import get_signal_request
from core.models import OperationLog
from counter.models import Selling, Refilling, Counter
def write_log(instance, operation_type):
def get_user():
request = get_signal_request()
if not request:
return None
# Get a random barmen if deletion is from a counter
session = getattr(request, "session", {})
session_token = session.get("counter_token", None)
if session_token:
counter = Counter.objects.filter(token=session_token).first()
if counter and len(counter.get_barmen_list()) > 0:
return counter.get_random_barman()
# Get the current logged user if not from a counter
if request.user and not request.user.is_anonymous:
return request.user
# Return None by default
return None
log = OperationLog(
label=str(instance), operator=get_user(), operation_type=operation_type,
).save()
@receiver(pre_delete, sender=Refilling, dispatch_uid="write_log_refilling_deletion")
def write_log_refilling_deletion(sender, instance, **kwargs):
write_log(instance, "REFILLING_DELETION")
@receiver(pre_delete, sender=Selling, dispatch_uid="write_log_refilling_deletion")
def write_log_selling_deletion(sender, instance, **kwargs):
write_log(instance, "SELLING_DELETION")
......@@ -6,7 +6,7 @@
msgid ""
msgstr ""
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-10-21 22:04+0200\n"
"POT-Creation-Date: 2019-11-13 23:14+0100\n"
"PO-Revision-Date: 2016-07-18\n"
"Last-Translator: Skia <skia@libskia.so>\n"
"Language-Team: AE info <ae.info@utbm.fr>\n"
......@@ -128,10 +128,10 @@ msgid "journal"
msgstr "classeur"
#: accounting/models.py:290 core/models.py:825 core/models.py:1363
#: core/models.py:1411 core/models.py:1440 counter/models.py:364
#: counter/models.py:457 counter/models.py:662 eboutic/models.py:46
#: eboutic/models.py:93 forum/models.py:311 forum/models.py:408
#: stock/models.py:104
#: core/models.py:1411 core/models.py:1440 core/models.py:1464
#: counter/models.py:364 counter/models.py:457 counter/models.py:662
#: eboutic/models.py:46 eboutic/models.py:93 forum/models.py:311
#: forum/models.py:408 stock/models.py:104
msgid "date"
msgstr "date"
......@@ -166,7 +166,8 @@ msgid "accounting type"
msgstr "type comptable"
#: accounting/models.py:328 accounting/models.py:475 accounting/models.py:510
#: accounting/models.py:545 core/models.py:1439 counter/models.py:423
#: accounting/models.py:545 core/models.py:1439 core/models.py:1465
#: counter/models.py:423
msgid "label"
msgstr "étiquette"
......@@ -218,7 +219,7 @@ msgstr "Compte"
msgid "Company"
msgstr "Entreprise"
#: accounting/models.py:341 sith/settings.py:380
#: accounting/models.py:341 sith/settings.py:379
#: stock/templates/stock/shopping_list_items.jinja:37
msgid "Other"
msgstr "Autre"
......@@ -316,7 +317,7 @@ msgstr "Liste des types comptable"
#: accounting/templates/accounting/label_list.jinja:10
#: accounting/templates/accounting/operation_edit.jinja:10
#: accounting/templates/accounting/simplifiedaccountingtype_list.jinja:10
#: core/templates/core/user_tools.jinja:57
#: core/templates/core/user_tools.jinja:58
msgid "Accounting"
msgstr "Comptabilité"
......@@ -335,7 +336,7 @@ msgstr "Il n'y a pas de types comptable dans ce site web."
#: accounting/templates/accounting/bank_account_details.jinja:4
#: accounting/templates/accounting/bank_account_details.jinja:14
#: core/templates/core/user_tools.jinja:66
#: core/templates/core/user_tools.jinja:67
msgid "Bank account: "
msgstr "Compte en banque : "
......@@ -425,7 +426,7 @@ msgstr "Nouveau compte club"
#: com/templates/com/weekmail.jinja:61 core/templates/core/file.jinja:38
#: core/templates/core/group_list.jinja:24 core/templates/core/page.jinja:35
#: core/templates/core/poster_list.jinja:40
#: core/templates/core/user_tools.jinja:42 core/views/user.py:228
#: core/templates/core/user_tools.jinja:43 core/views/user.py:228
#: counter/templates/counter/cash_summary_list.jinja:53
#: counter/templates/counter/counter_list.jinja:17
#: counter/templates/counter/counter_list.jinja:33
......@@ -531,7 +532,7 @@ msgid "Effective amount"
msgstr "Montant effectif"
#: accounting/templates/accounting/club_account_details.jinja:36
#: sith/settings.py:424
#: sith/settings.py:423
msgid "Closed"
msgstr "Fermé"
......@@ -576,7 +577,7 @@ msgstr "Voir"
#: accounting/templates/accounting/co_list.jinja:4
#: accounting/templates/accounting/journal_details.jinja:19
#: core/templates/core/user_tools.jinja:62
#: core/templates/core/user_tools.jinja:63
msgid "Company list"
msgstr "Liste des entreprises"
......@@ -631,7 +632,8 @@ msgstr "No"
#: core/templates/core/user_account_detail.jinja:78
#: counter/templates/counter/cash_summary_list.jinja:34
#: counter/templates/counter/last_ops.jinja:14
#: counter/templates/counter/last_ops.jinja:39 sas/views.py:369
#: counter/templates/counter/last_ops.jinja:39
#: rootplace/templates/rootplace/logs.jinja:12 sas/views.py:369
#: stock/templates/stock/stock_shopping_list.jinja:25
#: stock/templates/stock/stock_shopping_list.jinja:54
#: trombi/templates/trombi/user_profile.jinja:40
......@@ -642,6 +644,7 @@ msgstr "Date"
#: club/templates/club/club_sellings.jinja:24
#: core/templates/core/user_account_detail.jinja:20
#: counter/templates/counter/last_ops.jinja:42
#: rootplace/templates/rootplace/logs.jinja:14
msgid "Label"
msgstr "Étiquette"
......@@ -711,6 +714,7 @@ msgid "Accounting statement: "
msgstr "Bilan comptable : "
#: accounting/templates/accounting/journal_statement_accounting.jinja:15
#: rootplace/templates/rootplace/logs.jinja:13
msgid "Operation type"
msgstr "Type d'opération"
......@@ -1113,7 +1117,7 @@ msgid "inactive"
msgstr "inactif"
#: club/templates/club/club_list.jinja:34
#: core/templates/core/user_tools.jinja:23
#: core/templates/core/user_tools.jinja:24
msgid "New club"
msgstr "Nouveau club"
......@@ -1245,7 +1249,7 @@ msgid "Payment method"
msgstr "Méthode de paiement"
#: club/templates/club/club_tools.jinja:4
#: core/templates/core/user_tools.jinja:100
#: core/templates/core/user_tools.jinja:101
msgid "Club tools"
msgstr "Outils club"
......@@ -1272,7 +1276,7 @@ msgstr "Nouveau Trombi"
#: club/templates/club/club_tools.jinja:14
#: com/templates/com/poster_list.jinja:17
#: core/templates/core/poster_list.jinja:17
#: core/templates/core/user_tools.jinja:90
#: core/templates/core/user_tools.jinja:91
msgid "Posters"
msgstr "Affiches"
......@@ -1496,7 +1500,7 @@ msgid "Begin date should be before end date"
msgstr "La date de début doit être avant celle de fin"
#: com/templates/com/mailing_admin.jinja:4 com/views.py:131
#: core/templates/core/user_tools.jinja:89
#: core/templates/core/user_tools.jinja:90
msgid "Mailing lists administration"
msgstr "Administration des mailing listes"
......@@ -1544,7 +1548,7 @@ msgstr "Nouvelles"
#: com/templates/com/news_admin_list.jinja:11
#: com/templates/com/news_edit.jinja:8 com/templates/com/news_edit.jinja:31
#: core/templates/core/user_tools.jinja:84
#: core/templates/core/user_tools.jinja:85
msgid "Create news"
msgstr "Créer nouvelle"
......@@ -1792,7 +1796,7 @@ msgid "Screen - edit"
msgstr "Écran - modifier"
#: com/templates/com/screen_list.jinja:4 com/templates/com/screen_list.jinja:11
#: core/templates/core/user_tools.jinja:91
#: core/templates/core/user_tools.jinja:92
msgid "Screens"
msgstr "Écrans"
......@@ -1807,7 +1811,7 @@ msgid "Slideshow"
msgstr "Diaporama"
#: com/templates/com/weekmail.jinja:5 com/templates/com/weekmail.jinja:9
#: com/views.py:108 core/templates/core/user_tools.jinja:82
#: com/views.py:108 core/templates/core/user_tools.jinja:83
msgid "Weekmail"
msgstr "Weekmail"
......@@ -1905,7 +1909,7 @@ msgstr "Date de début"
msgid "Communication administration"
msgstr "Administration de la communication"
#: com/views.py:114 core/templates/core/user_tools.jinja:83
#: com/views.py:114 core/templates/core/user_tools.jinja:84
msgid "Weekmail destinations"
msgstr "Destinataires du Weekmail"
......@@ -2355,6 +2359,10 @@ msgstr "param"
msgid "viewed"
msgstr "vue"
#: core/models.py:1470
msgid "operation type"
msgstr "type d'opération"
#: core/templates/core/403.jinja:5
msgid "403, Forbidden"
msgstr "403, Non autorisé"
......@@ -2474,7 +2482,7 @@ msgstr "Photos"
#: eboutic/templates/eboutic/eboutic_main.jinja:24
#: eboutic/templates/eboutic/eboutic_makecommand.jinja:8
#: eboutic/templates/eboutic/eboutic_payment_result.jinja:4
#: sith/settings.py:379 sith/settings.py:387
#: sith/settings.py:378 sith/settings.py:386
msgid "Eboutic"
msgstr "Eboutic"
......@@ -2498,7 +2506,7 @@ msgstr "Laverie"
msgid "Files"
msgstr "Fichiers"
#: core/templates/core/base.jinja:189 core/templates/core/user_tools.jinja:108
#: core/templates/core/base.jinja:189 core/templates/core/user_tools.jinja:109
msgid "Pedagogy"
msgstr "Pédagogie"
......@@ -2687,7 +2695,7 @@ msgstr "Éditer le groupe"
#: core/templates/core/group_edit.jinja:9
#: core/templates/core/user_edit.jinja:37
#: core/templates/core/user_group.jinja:8
#: pedagogy/templates/pedagogy/uv_create.jinja:36
#: pedagogy/templates/pedagogy/uv_edit.jinja:36
msgid "Update"
msgstr "Mettre à jour"
......@@ -3054,7 +3062,7 @@ msgid "Eboutic invoices"
msgstr "Facture eboutic"
#: core/templates/core/user_account.jinja:57
#: core/templates/core/user_tools.jinja:36 counter/views.py:822
#: core/templates/core/user_tools.jinja:37 counter/views.py:822
msgid "Etickets"
msgstr "Etickets"
......@@ -3373,141 +3381,146 @@ msgid "Merge users"
msgstr "Fusionner deux utilisateurs"
#: core/templates/core/user_tools.jinja:16
#: rootplace/templates/rootplace/logs.jinja:5
msgid "Operation logs"
msgstr "Journal d'opérations"
#: core/templates/core/user_tools.jinja:17
#: rootplace/templates/rootplace/delete_user_messages.jinja:4
msgid "Delete user's forum messages"
msgstr "Supprimer les messages forum d'un utilisateur"
#: core/templates/core/user_tools.jinja:19
#: core/templates/core/user_tools.jinja:20
msgid "Subscriptions"
msgstr "Cotisations"
#: core/templates/core/user_tools.jinja:22
#: core/templates/core/user_tools.jinja:23
#: subscription/templates/subscription/stats.jinja:4
msgid "Subscription stats"
msgstr "Statistiques de cotisation"
#: core/templates/core/user_tools.jinja:28 counter/views.py:792
#: core/templates/core/user_tools.jinja:29 counter/views.py:792
#: counter/views.py:1000
msgid "Counters"
msgstr "Comptoirs"
#: core/templates/core/user_tools.jinja:31
#: core/templates/core/user_tools.jinja:32
msgid "General counters management"
msgstr "Gestion générale des comptoirs"
#: core/templates/core/user_tools.jinja:32
#: core/templates/core/user_tools.jinja:33
msgid "Products management"
msgstr "Gestion des produits"
#: core/templates/core/user_tools.jinja:33
#: core/templates/core/user_tools.jinja:34
msgid "Product types management"
msgstr "Gestion des types de produit"
#: core/templates/core/user_tools.jinja:34
#: core/templates/core/user_tools.jinja:35
#: counter/templates/counter/cash_summary_list.jinja:23 counter/views.py:812
msgid "Cash register summaries"
msgstr "Relevés de caisse"
#: core/templates/core/user_tools.jinja:35
#: core/templates/core/user_tools.jinja:36
#: counter/templates/counter/invoices_call.jinja:4 counter/views.py:817
msgid "Invoices call"
msgstr "Appels à facture"
#: core/templates/core/user_tools.jinja:43 core/views/user.py:277
#: core/templates/core/user_tools.jinja:44 core/views/user.py:277
#: counter/templates/counter/counter_list.jinja:18
#: counter/templates/counter/counter_list.jinja:34
#: counter/templates/counter/counter_list.jinja:56
msgid "Stats"
msgstr "Stats"
#: core/templates/core/user_tools.jinja:47
#: core/templates/core/user_tools.jinja:48
#: counter/templates/counter/counter_list.jinja:38
#: stock/templates/stock/stock_item_list.jinja:11
#: stock/templates/stock/stock_list.jinja:16
msgid "Shopping lists"
msgstr "Liste de courses"
#: core/templates/core/user_tools.jinja:49
#: core/templates/core/user_tools.jinja:50
#: counter/templates/counter/counter_list.jinja:40
msgid "Create new stock"
msgstr "Créer nouveau stock"
#: core/templates/core/user_tools.jinja:60
#: core/templates/core/user_tools.jinja:61
msgid "Refound Account"
msgstr "Rembourser un compte"
#: core/templates/core/user_tools.jinja:61
#: core/templates/core/user_tools.jinja:62
msgid "General accounting"
msgstr "Comptabilité générale"
#: core/templates/core/user_tools.jinja:71
#: core/templates/core/user_tools.jinja:72
msgid "Club account: "
msgstr "Compte club : "
#: core/templates/core/user_tools.jinja:78
#: core/templates/core/user_tools.jinja:79
msgid "Communication"
msgstr "Communication"
#: core/templates/core/user_tools.jinja:81
#: core/templates/core/user_tools.jinja:82
msgid "Create weekmail article"
msgstr "Rédiger un nouvel article dans le Weekmail"
#: core/templates/core/user_tools.jinja:85
#: core/templates/core/user_tools.jinja:86
msgid "Moderate news"
msgstr "Modérer les nouvelles"
#: core/templates/core/user_tools.jinja:86
#: core/templates/core/user_tools.jinja:87
msgid "Edit alert message"
msgstr "Éditer le message d'alerte"
#: core/templates/core/user_tools.jinja:87
#: core/templates/core/user_tools.jinja:88
msgid "Edit information message"
msgstr "Éditer le message d'informations"
#: core/templates/core/user_tools.jinja:88
#: core/templates/core/user_tools.jinja:89
msgid "Moderate files"
msgstr "Modérer les fichiers"
#: core/templates/core/user_tools.jinja:94
#: core/templates/core/user_tools.jinja:95
msgid "Moderate pictures"
msgstr "Modérer les photos"
#: core/templates/core/user_tools.jinja:111
#: core/templates/core/user_tools.jinja:112
#: pedagogy/templates/pedagogy/guide.jinja:20
msgid "Create UV"
msgstr "Créer UV"
#: core/templates/core/user_tools.jinja:112
#: core/templates/core/user_tools.jinja:113
#: pedagogy/templates/pedagogy/guide.jinja:23
#: trombi/templates/trombi/detail.jinja:10
msgid "Moderate comments"
msgstr "Modérer les commentaires"
#: core/templates/core/user_tools.jinja:117
#: core/templates/core/user_tools.jinja:118
msgid "Elections"
msgstr "Élections"
#: core/templates/core/user_tools.jinja:119
#: core/templates/core/user_tools.jinja:120
msgid "See available elections"
msgstr "Voir les élections disponibles"
#: core/templates/core/user_tools.jinja:120
#: core/templates/core/user_tools.jinja:121
msgid "See archived elections"
msgstr "Voir les élections archivées"