diff --git a/kfet/auth/fields.py b/kfet/auth/fields.py index a5544787..4c842b85 100644 --- a/kfet/auth/fields.py +++ b/kfet/auth/fields.py @@ -1,17 +1,24 @@ from django import forms -from django.contrib.auth.models import Permission -from django.contrib.contenttypes.models import ContentType -from django.forms import widgets +from django.contrib.auth.models import Group + +from .models import KFetPermission class KFetPermissionsField(forms.ModelMultipleChoiceField): def __init__(self, *args, **kwargs): - queryset = Permission.objects.filter( - content_type__in=ContentType.objects.filter(app_label="kfet") - ) - super().__init__( - queryset=queryset, widget=widgets.CheckboxSelectMultiple, *args, **kwargs - ) + kwargs.setdefault("queryset", KFetPermission.objects.all()) + kwargs.setdefault("widget", forms.CheckboxSelectMultiple) + super().__init__(*args, **kwargs) + + def label_from_instance(self, obj): + return obj.name + + +class KFetGroupsField(forms.ModelMultipleChoiceField): + def __init__(self, *args, **kwargs): + kwargs.setdefault("queryset", Group.objects.filter(kfetgroup__isnull=False)) + kwargs.setdefault("widget", forms.SelectMultiple) + super().__init__(*args, **kwargs) def label_from_instance(self, obj): return obj.name diff --git a/kfet/auth/forms.py b/kfet/auth/forms.py index b1628af0..33f5a260 100644 --- a/kfet/auth/forms.py +++ b/kfet/auth/forms.py @@ -1,48 +1,29 @@ -from django import forms -from django.contrib.auth.models import Group, User +from django.contrib.auth.models import User +from django.utils.translation import ugettext_lazy as _ -from .fields import KFetPermissionsField +from shared.forms import ProtectedModelForm + +from .fields import KFetGroupsField, KFetPermissionsField +from .models import KFetGroup -class GroupForm(forms.ModelForm): +class GroupForm(ProtectedModelForm): permissions = KFetPermissionsField() - def clean_name(self): - name = self.cleaned_data["name"] - return "K-Fêt %s" % name - - def clean_permissions(self): - kfet_perms = self.cleaned_data["permissions"] - # TODO: With Django >=1.11, the QuerySet method 'difference' can be - # used. - # other_groups = self.instance.permissions.difference( - # self.fields['permissions'].queryset - # ) - if self.instance.pk is None: - return kfet_perms - other_perms = self.instance.permissions.exclude( - pk__in=[p.pk for p in self.fields["permissions"].queryset] - ) - return list(kfet_perms) + list(other_perms) + protected_fields = ["permissions"] class Meta: - model = Group + model = KFetGroup fields = ["name", "permissions"] -class UserGroupForm(forms.ModelForm): - groups = forms.ModelMultipleChoiceField( - Group.objects.filter(name__icontains="K-Fêt"), - label="Statut équipe", +class UserGroupForm(ProtectedModelForm): + groups = KFetGroupsField( + label=_("Statut équipe"), required=False, ) - def clean_groups(self): - kfet_groups = self.cleaned_data.get("groups") - if self.instance.pk is None: - return kfet_groups - other_groups = self.instance.groups.exclude(name__icontains="K-Fêt") - return list(kfet_groups) + list(other_groups) + protected_fields = ["groups"] class Meta: model = User diff --git a/kfet/auth/migrations/0002_kfetgroup_kfetpermission.py b/kfet/auth/migrations/0002_kfetgroup_kfetpermission.py new file mode 100644 index 00000000..48c680d0 --- /dev/null +++ b/kfet/auth/migrations/0002_kfetgroup_kfetpermission.py @@ -0,0 +1,55 @@ +# Generated by Django 2.2.8 on 2020-01-08 21:03 + +import django.contrib.auth.models +import django.db.models.deletion +import django.db.models.manager +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("auth", "0011_update_proxy_permissions"), + ("kfetauth", "0001_initial"), + ] + + operations = [ + migrations.CreateModel( + name="KFetGroup", + fields=[ + ( + "group_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="auth.Group", + ), + ), + ], + options={ + "verbose_name": "Groupe K-Fêt", + "verbose_name_plural": "Groupes K-Fêt", + }, + bases=("auth.group",), + managers=[("objects", django.contrib.auth.models.GroupManager())], + ), + migrations.CreateModel( + name="KFetPermission", + fields=[], + options={ + "verbose_name": "Permission K-Fêt", + "verbose_name_plural": "Permissions K-Fêt", + "proxy": True, + "indexes": [], + "constraints": [], + }, + bases=("auth.permission",), + managers=[ + ("kfet", django.db.models.manager.Manager()), + ("objects", django.contrib.auth.models.PermissionManager()), + ], + ), + ] diff --git a/kfet/auth/migrations/0003_existing_groups.py b/kfet/auth/migrations/0003_existing_groups.py new file mode 100644 index 00000000..855a9c19 --- /dev/null +++ b/kfet/auth/migrations/0003_existing_groups.py @@ -0,0 +1,21 @@ +# Generated by Django 2.2.8 on 2020-01-08 21:04 + +from django.db import migrations + + +def existing_groups(apps, schema_editor): + Group = apps.get_model("auth", "Group") + KFetGroup = apps.get_model("kfetauth", "KFetGroup") + + for group in Group.objects.filter(name__icontains="K-Fêt"): + kf_group = KFetGroup(group_ptr=group, pk=group.pk, name=group.name) + kf_group.save() + + +class Migration(migrations.Migration): + + dependencies = [ + ("kfetauth", "0002_kfetgroup_kfetpermission"), + ] + + operations = [migrations.RunPython(existing_groups)] diff --git a/kfet/auth/models.py b/kfet/auth/models.py index 73a70c22..865852cd 100644 --- a/kfet/auth/models.py +++ b/kfet/auth/models.py @@ -1,5 +1,9 @@ +from django.contrib.auth.models import Group, Permission from django.db import models from django.utils.crypto import get_random_string +from django.utils.translation import ugettext_lazy as _ + +KFET_APP_LABELS = ["kfet", "kfetauth"] class GenericTeamTokenManager(models.Manager): @@ -14,3 +18,28 @@ class GenericTeamToken(models.Model): token = models.CharField(max_length=50, unique=True) objects = GenericTeamTokenManager() + + +class KFetPermissionManager(models.Manager): + def get_queryset(self): + return ( + super().get_queryset().filter(content_type__app_label__in=KFET_APP_LABELS) + ) + + +class KFetPermission(Permission): + objects = KFetPermissionManager() + + class Meta: + proxy = True + verbose_name = _("Permission K-Fêt") + verbose_name_plural = _("Permissions K-Fêt") + + +class KFetGroup(Group): + # On fait un héritage complet pour + # mieux distinguer les groupes K-Fêt via l'ORM (i.e. faire `KFetGroup.objects.all`) + + class Meta: + verbose_name = _("Groupe K-Fêt") + verbose_name_plural = _("Groupes K-Fêt") diff --git a/kfet/auth/tests.py b/kfet/auth/tests.py index 6fb1125e..32e04812 100644 --- a/kfet/auth/tests.py +++ b/kfet/auth/tests.py @@ -10,7 +10,7 @@ from kfet.models import Account from . import KFET_GENERIC_TRIGRAMME, KFET_GENERIC_USERNAME from .backends import AccountBackend, GenericBackend -from .models import GenericTeamToken +from .models import GenericTeamToken, KFetGroup from .utils import get_kfet_generic_user from .views import GenericLoginView @@ -27,11 +27,8 @@ class UserGroupFormTests(TestCase): self.user = User.objects.create(username="foo", password="foo") # create some K-Fêt groups - prefix_name = "K-Fêt " names = ["Group 1", "Group 2", "Group 3"] - self.kfet_groups = [ - Group.objects.create(name=prefix_name + name) for name in names - ] + self.kfet_groups = [KFetGroup.objects.create(name=name) for name in names] # create a non-K-Fêt group self.other_group = Group.objects.create(name="Other group") @@ -41,7 +38,9 @@ class UserGroupFormTests(TestCase): form = UserGroupForm(instance=self.user) groups_field = form.fields["groups"] self.assertQuerysetEqual( - groups_field.queryset, [repr(g) for g in self.kfet_groups], ordered=False + groups_field.queryset, + [repr(g.group_ptr) for g in self.kfet_groups], + ordered=False, ) def test_keep_others(self): @@ -59,7 +58,8 @@ class UserGroupFormTests(TestCase): form.save() self.assertQuerysetEqual( user.groups.all(), - [repr(g) for g in [self.other_group] + self.kfet_groups], + [self.other_group.pk] + [group.pk for group in self.kfet_groups], + transform=lambda group: group.pk, ordered=False, ) diff --git a/kfet/auth/views.py b/kfet/auth/views.py index 5dd048e9..f57e8415 100644 --- a/kfet/auth/views.py +++ b/kfet/auth/views.py @@ -1,7 +1,7 @@ from django.contrib import messages from django.contrib.auth import authenticate, login from django.contrib.auth.decorators import permission_required -from django.contrib.auth.models import Group, User +from django.contrib.auth.models import User from django.contrib.auth.views import redirect_to_login from django.contrib.messages.views import SuccessMessageMixin from django.db.models import Prefetch @@ -15,7 +15,7 @@ from django.views.generic import View from django.views.generic.edit import CreateView, UpdateView from .forms import GroupForm -from .models import GenericTeamToken +from .models import GenericTeamToken, KFetGroup class GenericLoginView(View): @@ -113,23 +113,20 @@ def account_group(request): user_pre = Prefetch( "user_set", queryset=User.objects.select_related("profile__account_kfet") ) - groups = Group.objects.filter(name__icontains="K-Fêt").prefetch_related( - "permissions", user_pre - ) + groups = KFetGroup.objects.prefetch_related("permissions", user_pre) return render(request, "kfet/account_group.html", {"groups": groups}) -class AccountGroupCreate(SuccessMessageMixin, CreateView): - model = Group +class AccountGroupFormMixin(SuccessMessageMixin): + model = KFetGroup template_name = "kfet/account_group_form.html" form_class = GroupForm + success_url = reverse_lazy("kfet.account.group") + + +class AccountGroupCreate(AccountGroupFormMixin, CreateView): success_message = "Nouveau groupe : %(name)s" - success_url = reverse_lazy("kfet.account.group") -class AccountGroupUpdate(SuccessMessageMixin, UpdateView): - queryset = Group.objects.filter(name__icontains="K-Fêt") - template_name = "kfet/account_group_form.html" - form_class = GroupForm +class AccountGroupUpdate(AccountGroupFormMixin, UpdateView): success_message = "Groupe modifié : %(name)s" - success_url = reverse_lazy("kfet.account.group") diff --git a/kfet/management/commands/loadkfetdevdata.py b/kfet/management/commands/loadkfetdevdata.py index 9c1425b4..43b14b09 100644 --- a/kfet/management/commands/loadkfetdevdata.py +++ b/kfet/management/commands/loadkfetdevdata.py @@ -6,12 +6,13 @@ import os import random from datetime import timedelta -from django.contrib.auth.models import Group, Permission, User +from django.contrib.auth.models import User from django.core.management import call_command from django.utils import timezone from gestioncof.management.base import MyBaseCommand from gestioncof.models import CofProfile +from kfet.auth.models import KFetGroup, KFetPermission from kfet.models import ( Account, Article, @@ -33,23 +34,17 @@ class Command(MyBaseCommand): # Groupes # --- - Group.objects.filter(name__icontains="K-Fêt").delete() + group_chef, _ = KFetGroup.objects.get_or_create(name="K-Fêt César") + group_boy, _ = KFetGroup.objects.get_or_create(name="K-Fêt Légionnaire") - group_chef = Group(name="K-Fêt César") - group_boy = Group(name="K-Fêt Légionnaire") + # Give relevant permissions to both groups + chef_perms = KFetPermission.objects.all() + group_chef.permissions.add(*chef_perms) - group_chef.save() - group_boy.save() - - permissions_chef = Permission.objects.filter( - content_type__app_label="kfet", + boy_perms = KFetPermission.objects.filter( + codename__in=["is_team", "perform_deposit", "add_account", "add_transfer"] ) - permissions_boy = Permission.objects.filter( - content_type__app_label="kfet", codename__in=["is_team", "perform_deposit"] - ) - - group_chef.permissions.add(*permissions_chef) - group_boy.permissions.add(*permissions_boy) + group_boy.permissions.add(*boy_perms) # --- # Comptes diff --git a/kfet/templates/kfet/account_group_form.html b/kfet/templates/kfet/account_group_form.html index b309d838..7d1410dd 100644 --- a/kfet/templates/kfet/account_group_form.html +++ b/kfet/templates/kfet/account_group_form.html @@ -7,35 +7,6 @@ {% block main %} -
- {% csrf_token %} -
- -
-
- K-Fêt - {{ form.name|add_class:"form-control" }} -
- {% if form.name.errors %} - {{ form.name.errors }} - {% endif %} - {% if form.name.help_text %} - {{ form.name.help_text }} - {% endif %} -
-
- {% include "kfet/form_field_snippet.html" with field=form.permissions %} - {% include "kfet/form_submit_snippet.html" with value="Enregistrer" %} -
- - +{% include "kfet/form_full_snippet.html" with authz=perms.kfet.manage_perms submit_text="Enregistrer" %} {% endblock %} diff --git a/kfet/templates/kfet/form_field_snippet.html b/kfet/templates/kfet/form_field_snippet.html index a2aa087f..b7eddb5d 100644 --- a/kfet/templates/kfet/form_field_snippet.html +++ b/kfet/templates/kfet/form_field_snippet.html @@ -5,7 +5,7 @@
{% if field|widget_type == "checkboxselectmultiple" %}