Merge branch 'dodo/limit-history-acces' into 'master'

Limit kfet history access

See merge request klub-dev-ens/gestioCOF!487
This commit is contained in:
Ludovic Stephan 2021-02-20 22:58:59 +01:00
commit 778637d60e
8 changed files with 100 additions and 7 deletions

View file

@ -23,6 +23,10 @@ adhérents ni des cotisations.
## Version ??? - dans un futur proche ## Version ??? - dans un futur proche
### K-Fêt
- L'accès à l'historique est maintenant limité à 7 jours pour raison de confidentialité. Les chefs/trez peuvent disposer d'une permission supplémentaire pour accèder à jusqu'à 30 jours en cas de problème de compta. L'accès à son historique personnel n'est pas limité. Les durées sont configurables dans `settings/cof_prod.py`.
## Version 0.9 - 06/02/2020 ## Version 0.9 - 06/02/2020
### COF / BdA ### COF / BdA

View file

@ -5,6 +5,7 @@ Surcharge les settings définis dans common.py
""" """
import os import os
from datetime import timedelta
from .common import * # NOQA from .common import * # NOQA
from .common import ( from .common import (
@ -202,3 +203,15 @@ MAIL_DATA = {
"REPLYTO": "BdA-Revente <bda-revente@ens.fr>", "REPLYTO": "BdA-Revente <bda-revente@ens.fr>",
}, },
} }
# ---
# kfet history limits
# ---
# L'historique n'est accesible que d'aujourd'hui
# à aujourd'hui - KFET_HISTORY_DATE_LIMIT
KFET_HISTORY_DATE_LIMIT = timedelta(days=7)
# Limite plus longue pour les chefs/trez
# (qui ont la permission kfet.access_old_history)
KFET_HISTORY_LONG_DATE_LIMIT = timedelta(days=30)

View file

@ -2,6 +2,7 @@ from datetime import timedelta
from decimal import Decimal from decimal import Decimal
from django import forms from django import forms
from django.conf import settings
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.core import validators from django.core import validators
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
@ -484,7 +485,15 @@ class KFetConfigForm(ConfigForm):
class FilterHistoryForm(forms.Form): class FilterHistoryForm(forms.Form):
start = forms.DateTimeField(label=_("De"), widget=DateTimeWidget, required=False) start = forms.DateTimeField(
label=_("De"),
widget=DateTimeWidget,
required=False,
help_text="Limité à {} jours ({} pour les chefs/trez)".format(
settings.KFET_HISTORY_DATE_LIMIT.days,
settings.KFET_HISTORY_LONG_DATE_LIMIT.days,
),
)
end = forms.DateTimeField(label=_("À"), widget=DateTimeWidget, required=False) end = forms.DateTimeField(label=_("À"), widget=DateTimeWidget, required=False)
checkout = forms.ModelChoiceField( checkout = forms.ModelChoiceField(
label=_("Caisse"), label=_("Caisse"),

View file

@ -0,0 +1,36 @@
# Generated by Django 2.2.17 on 2021-02-19 12:37
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("kfet", "0073_2021"),
]
operations = [
migrations.AlterModelOptions(
name="account",
options={
"permissions": (
("is_team", "Is part of the team"),
("manage_perms", "Gérer les permissions K-Fêt"),
("manage_addcosts", "Gérer les majorations"),
("edit_balance_account", "Modifier la balance d'un compte"),
(
"change_account_password",
"Modifier le mot de passe d'une personne de l'équipe",
),
(
"special_add_account",
"Créer un compte avec une balance initiale",
),
("can_force_close", "Fermer manuellement la K-Fêt"),
("see_config", "Voir la configuration K-Fêt"),
("change_config", "Modifier la configuration K-Fêt"),
("access_old_history", "Peut accéder à l'historique plus ancien"),
)
},
),
]

View file

@ -89,6 +89,7 @@ class Account(models.Model):
("can_force_close", "Fermer manuellement la K-Fêt"), ("can_force_close", "Fermer manuellement la K-Fêt"),
("see_config", "Voir la configuration K-Fêt"), ("see_config", "Voir la configuration K-Fêt"),
("change_config", "Modifier la configuration K-Fêt"), ("change_config", "Modifier la configuration K-Fêt"),
("access_old_history", "Peut accéder à l'historique plus ancien"),
) )
def __str__(self): def __str__(self):

View file

@ -62,6 +62,7 @@ $(document).ready(function() {
format : 'YYYY-MM-DD HH:mm', format : 'YYYY-MM-DD HH:mm',
stepping : 5, stepping : 5,
locale : 'fr', locale : 'fr',
minDate : '{{ history_limit }}',
showTodayButton: true, showTodayButton: true,
widgetPositioning: { widgetPositioning: {
horizontal: "left", horizontal: "left",

View file

@ -4219,8 +4219,8 @@ class HistoryJSONViewTests(ViewTestCaseMixin, TestCase):
url_name = "kfet.history.json" url_name = "kfet.history.json"
url_expected = "/k-fet/history.json" url_expected = "/k-fet/history.json"
auth_user = "user" auth_user = "team"
auth_forbidden = [None, "noaccount"] auth_forbidden = [None, "user", "noaccount"]
def test_ok(self): def test_ok(self):
r = self.client.post(self.url) r = self.client.post(self.url)

View file

@ -1,11 +1,12 @@
import heapq import heapq
import statistics import statistics
from collections import defaultdict from collections import defaultdict
from datetime import timedelta from datetime import datetime, timedelta
from decimal import Decimal from decimal import Decimal
from typing import List from typing import List
from urllib.parse import urlencode from urllib.parse import urlencode
from django.conf import settings
from django.contrib import messages from django.contrib import messages
from django.contrib.auth.decorators import login_required, permission_required from django.contrib.auth.decorators import login_required, permission_required
from django.contrib.auth.mixins import PermissionRequiredMixin from django.contrib.auth.mixins import PermissionRequiredMixin
@ -1410,6 +1411,18 @@ def cancel_operations(request):
return JsonResponse(data) return JsonResponse(data)
def get_history_limit(user) -> datetime:
"""returns the earliest date the given user can view history
according to his/her permissions"""
now = timezone.now()
if user.has_perm("kfet.access_old_history"):
return now - settings.KFET_HISTORY_LONG_DATE_LIMIT
if user.has_perm("kfet.is_team"):
return now - settings.KFET_HISTORY_LONG_DATE_LIMIT
# should not happen - future earliest date
return now + timedelta(days=1)
@login_required @login_required
def history_json(request): def history_json(request):
# Récupération des paramètres # Récupération des paramètres
@ -1468,6 +1481,9 @@ def history_json(request):
.order_by("at") .order_by("at")
) )
# limite l'accès à l'historique plus vieux que settings.KFET_HISTORY_DATE_LIMIT
limit_date = True
# Application des filtres # Application des filtres
if start: if start:
opegroups = opegroups.filter(at__gte=start) opegroups = opegroups.filter(at__gte=start)
@ -1484,9 +1500,18 @@ def history_json(request):
transfergroups = TransferGroup.objects.none() transfergroups = TransferGroup.objects.none()
if account: if account:
opegroups = opegroups.filter(on_acc=account) opegroups = opegroups.filter(on_acc=account)
if account.user == request.user:
limit_date = False # pas de limite de date sur son propre historique
# Un non-membre de l'équipe n'a que accès à son historique # Un non-membre de l'équipe n'a que accès à son historique
if not request.user.has_perm("kfet.is_team"): elif not request.user.has_perm("kfet.is_team"):
opegroups = opegroups.filter(on_acc=request.user.profile.account_kfet) # un non membre de la kfet doit avoir le champ account
# pré-rempli, cette requête est douteuse
return JsonResponse({}, status=403)
if limit_date:
# limiter l'accès à l'historique ancien pour confidentialité
earliest_date = get_history_limit(request.user)
opegroups = opegroups.filter(at__gte=earliest_date)
transfergroups = transfergroups.filter(at__gte=earliest_date)
# Construction de la réponse # Construction de la réponse
history_groups = [] history_groups = []
@ -1576,7 +1601,11 @@ def kpsul_articles_data(request):
@teamkfet_required @teamkfet_required
def history(request): def history(request):
data = {"filter_form": FilterHistoryForm()} history_limit = get_history_limit(request.user)
data = {
"filter_form": FilterHistoryForm(),
"history_limit": history_limit.strftime("%Y-%m-%d %H:%M"),
}
return render(request, "kfet/history.html", data) return render(request, "kfet/history.html", data)