From 29d288c567d5bedcf45cd1d5af98ff8dae751bfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Delobelle?= Date: Tue, 5 Sep 2017 15:02:33 +0200 Subject: [PATCH 1/2] Fix permissions setup of associations. - Permissions of 'gestion' app are correctly added to the staff groups of associations. - Add tests to ensure staff groups of COF and BDS are correctly setup. - Shortcut functions are added to retrieve COF and BDS association. --- bds/apps.py | 36 ++++++----------------- bds/models.py | 6 +++- cof/apps.py | 36 ++++++----------------- cof/models.py | 7 ++++- gestion/apps.py | 11 +++++++ gestion/models.py | 47 ++++++++++++++++++++++++++++-- gestion/tests.py | 74 ++++++++++++++++++++++++++++++++++++++++++----- 7 files changed, 152 insertions(+), 65 deletions(-) diff --git a/bds/apps.py b/bds/apps.py index 525776ec..6a44ae3d 100644 --- a/bds/apps.py +++ b/bds/apps.py @@ -1,36 +1,18 @@ from django.apps import AppConfig from django.db.models.signals import post_migrate - -def setup_groups(sender, apps, **kwargs): - """ - Add the appropriate permissions to the "member" and "buro" groups after the - `post_migrate` signal since the permissions will only be inserted in the - database at the very end of the migrations. - """ - Group = apps.get_model("auth", "Group") - Permission = apps.get_model("auth", "Permission") - - # Buro members have perms bds.* and gestion.* - buro, _ = Group.objects.get_or_create(name="bds_buro") - app_perms = Permission.objects.filter( - content_type__app_label__in=["cof", "gestion"] - ) - buro.permissions.add(*app_perms) - - # Members have perm bds.member - members, _ = Group.objects.get_or_create(name="bds_members") - perm = Permission.objects.get( - codename="member", - content_type__app_label="bds" - ) - members.permissions.add(perm) +from gestion.apps import setup_assoc_perms class BDSConfig(AppConfig): name = "bds" verbose_name = "Application de gestion du BDS" - def ready(self): - # https://docs.djangoproject.com/en/1.11/ref/signals/#post-migrate - post_migrate.connect(setup_groups, sender=self) + +def setup_bds_perms(sender, apps, **kwargs): + from bds.models import get_bds_assoc + setup_assoc_perms(apps, get_bds_assoc, buro_of_apps=['gestion', 'bds']) + +# Setup permissions of defaults groups of BDS association after Permission +# instances have been created, i.e. after applying migrations. +post_migrate.connect(setup_bds_perms) diff --git a/bds/models.py b/bds/models.py index da80dd77..30053ea8 100644 --- a/bds/models.py +++ b/bds/models.py @@ -3,7 +3,11 @@ import os.path from django.utils import timezone from django.db import models -from gestion.models import Profile +from gestion.models import Association, Profile + + +def get_bds_assoc(): + return Association.objects.get(name='BDS') class BdsProfile(models.Model): diff --git a/cof/apps.py b/cof/apps.py index c40e8896..976bcf79 100644 --- a/cof/apps.py +++ b/cof/apps.py @@ -1,36 +1,18 @@ from django.apps import AppConfig from django.db.models.signals import post_migrate - -def setup_groups(sender, apps, **kwargs): - """ - Add the appropriate permissions to the "member" and "buro" groups after the - `post_migrate` signal since the permissions will only be inserted in the - database at the very end of the migrations. - """ - Group = apps.get_model("auth", "Group") - Permission = apps.get_model("auth", "Permission") - - # Buro members have perms cof.* and gestion.* - buro, _ = Group.objects.get_or_create(name="cof_buro") - app_perms = Permission.objects.filter( - content_type__app_label__in=["cof", "gestion"] - ) - buro.permissions.add(*app_perms) - - # Members have perm cof.member - members, _ = Group.objects.get_or_create(name="cof_members") - perm = Permission.objects.get( - codename="member", - content_type__app_label="cof" - ) - members.permissions.add(perm) +from gestion.apps import setup_assoc_perms class COFConfig(AppConfig): name = "cof" verbose_name = "Application de gestion du COF" - def ready(self): - # https://docs.djangoproject.com/en/1.11/ref/signals/#post-migrate - post_migrate.connect(setup_groups, sender=self) + +def setup_cof_perms(sender, apps, **kwargs): + from cof.models import get_cof_assoc + setup_assoc_perms(apps, get_cof_assoc, buro_of_apps=['gestion', 'cof']) + +# Setup permissions of defaults groups of BDS association after Permission +# instances have been created, i.e. after applying migrations. +post_migrate.connect(setup_cof_perms) diff --git a/cof/models.py b/cof/models.py index bdbd0e1b..4aba0ad3 100644 --- a/cof/models.py +++ b/cof/models.py @@ -6,11 +6,16 @@ from django.utils.translation import ugettext_lazy as _ from django.utils.encoding import python_2_unicode_compatible import django.utils.six as six -from gestion.models import Profile +from gestion.models import Association, Profile from bda.models import Spectacle from .petits_cours_models import choices_length + +def get_cof_assoc(): + return Association.objects.get(name='COF') + + TYPE_COTIZ_CHOICES = ( ('etudiant', _("Normalien étudiant")), ('normalien', _("Normalien élève")), diff --git a/gestion/apps.py b/gestion/apps.py index efb14b29..bc5967b0 100644 --- a/gestion/apps.py +++ b/gestion/apps.py @@ -4,3 +4,14 @@ from django.apps import AppConfig class GestionConfig(AppConfig): name = "gestion" verbose_name = "Gestion des outils communs COF/BDS" + + +def setup_assoc_perms(apps, assoc_getter, buro_of_apps=[], **kwargs): + try: + # Association and Permission models are required to be ready to setup + # perms. + apps.get_app_config('gestion') + apps.get_app_config('auth') + except LookupError: + return + assoc_getter().setup_perms(buro_of_apps=buro_of_apps) diff --git a/gestion/models.py b/gestion/models.py index d00cbec8..893c21c2 100644 --- a/gestion/models.py +++ b/gestion/models.py @@ -1,7 +1,7 @@ -from django.contrib.auth.models import User, Group +from django.contrib.auth.models import Group, Permission, User from django.db import models +from django.db.models.signals import post_delete, post_save from django.dispatch import receiver -from django.db.models.signals import post_save, post_delete from django.urls import reverse from django.utils.translation import ugettext_lazy as _ @@ -105,6 +105,49 @@ class Association(models.Model): def __str__(self): return self.name + def setup_perms(self, buro_of_apps=[]): + """ + Setup permissions of the staff and members groups. + + Permission '.member' is added to the 'members_group' of + the association. + + Permission '.buro' is added to the 'staff_group' of the + association. All permissions of applications from 'buro_of_apps' are + also added to this group. + + Arguments + buro_of_apps (list of 'app_label', optional) + + Should be used in receiver of 'post_migrate' signal, after permissions + creation. + + """ + def try_add_perm(group, app_label, codename): + try: + perm = Permission.objects.get( + content_type__app_label=app_label, + codename=codename, + ) + except Permission.DoesNotExist: + pass + else: + group.permissions.add(perm) + + app_label = self.name.lower() + + # Buro group has perm '.buro'. + try_add_perm(self.staff_group, app_label, 'buro') + + # Add all permissions of applications given 'buro_of_apps'. + apps_perms = Permission.objects.filter( + content_type__app_label__in=buro_of_apps, + ) + self.staff_group.permissions.add(*apps_perms) + + # Members have perm '.member'. + try_add_perm(self.members_group, app_label, 'member') + # --- # Clubs diff --git a/gestion/tests.py b/gestion/tests.py index 21e532ed..755b4f3b 100644 --- a/gestion/tests.py +++ b/gestion/tests.py @@ -1,16 +1,18 @@ # -*- coding: utf-8 -*- -""" -This file demonstrates writing tests using the unittest module. These will pass -when you run "manage.py test". - -Replace this with more appropriate tests for your application. -""" from unittest.mock import patch +from django.contrib.auth import get_user_model +from django.contrib.auth.models import Permission from django.db.utils import IntegrityError from django.test import Client, TestCase -from gestion.models import Profile, User +from bds.models import get_bds_assoc +from cof.models import get_cof_assoc + +from .models import Profile + + +User = get_user_model() def create_profile(username): @@ -120,3 +122,61 @@ class AuthTest(TestCase): resp.url.split('?')[0], "https://cas.eleves.ens.fr/login" ) + + +class AssociationTests(TestCase): + + def setUp(self): + self.gestion_p = Permission.objects.filter( + content_type__app_label='gestion', + ) + + def assertAllAppPerms(self, group, app_label): + group_p = group.permissions.all() + app_p = Permission.objects.filter( + content_type__app_label=app_label, + ) + for perm in app_p: + self.assertIn(perm, group_p) + + def test_cof_assoc(self): + cof_assoc = get_cof_assoc() + + # Check cof buro group has 'cof.buro' permission. + buro_perm = Permission.objects.get( + content_type__app_label='cof', + codename='buro', + ) + self.assertIn(buro_perm, cof_assoc.staff_group.permissions.all()) + + # Check cof buro group has all permissions of 'gestion' and 'cof' apps. + self.assertAllAppPerms(cof_assoc.staff_group, 'cof') + self.assertAllAppPerms(cof_assoc.staff_group, 'gestion') + + # Check cof members group has 'cof.member' permission. + member_perm = Permission.objects.get( + content_type__app_label='cof', + codename='member', + ) + self.assertIn(member_perm, cof_assoc.members_group.permissions.all()) + + def test_bds_assoc(self): + bds_assoc = get_bds_assoc() + + # Check cof buro group has 'bds.buro' permission. + buro_perm = Permission.objects.get( + content_type__app_label='bds', + codename='buro', + ) + self.assertIn(buro_perm, bds_assoc.staff_group.permissions.all()) + + # Check bds buro group has all permissions of 'gestion' and 'bds' apps. + self.assertAllAppPerms(bds_assoc.staff_group, 'bds') + self.assertAllAppPerms(bds_assoc.staff_group, 'gestion') + + # Check cof members group has 'bds.member' permission. + member_perm = Permission.objects.get( + content_type__app_label='bds', + codename='member', + ) + self.assertIn(member_perm, bds_assoc.members_group.permissions.all()) From 52aadc636b66fa44a83be6f80ce1bfc07fc95ec4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Sat, 9 Sep 2017 15:55:22 +0200 Subject: [PATCH 2/2] Add custommail perms to staff groups --- bds/apps.py | 6 +++++- cof/apps.py | 6 +++++- cof/settings/secret.py | 1 + gestion/apps.py | 4 ++-- gestion/models.py | 14 ++++++++++---- gestion/tests.py | 13 +++++++++++-- 6 files changed, 34 insertions(+), 10 deletions(-) create mode 120000 cof/settings/secret.py diff --git a/bds/apps.py b/bds/apps.py index 6a44ae3d..86d97b09 100644 --- a/bds/apps.py +++ b/bds/apps.py @@ -11,7 +11,11 @@ class BDSConfig(AppConfig): def setup_bds_perms(sender, apps, **kwargs): from bds.models import get_bds_assoc - setup_assoc_perms(apps, get_bds_assoc, buro_of_apps=['gestion', 'bds']) + setup_assoc_perms( + apps, get_bds_assoc, + buro_of_apps=['gestion', 'bds'], + perms=["custommail.add_custommail", "custommail.change_custommail"] + ) # Setup permissions of defaults groups of BDS association after Permission # instances have been created, i.e. after applying migrations. diff --git a/cof/apps.py b/cof/apps.py index 976bcf79..98cffdd9 100644 --- a/cof/apps.py +++ b/cof/apps.py @@ -11,7 +11,11 @@ class COFConfig(AppConfig): def setup_cof_perms(sender, apps, **kwargs): from cof.models import get_cof_assoc - setup_assoc_perms(apps, get_cof_assoc, buro_of_apps=['gestion', 'cof']) + setup_assoc_perms( + apps, get_cof_assoc, + buro_of_apps=['gestion', 'cof'], + perms=["custommail.add_custommail", "custommail.change_custommail"] + ) # Setup permissions of defaults groups of BDS association after Permission # instances have been created, i.e. after applying migrations. diff --git a/cof/settings/secret.py b/cof/settings/secret.py new file mode 120000 index 00000000..f1c3d3f7 --- /dev/null +++ b/cof/settings/secret.py @@ -0,0 +1 @@ +secret_example.py \ No newline at end of file diff --git a/gestion/apps.py b/gestion/apps.py index bc5967b0..c27b7265 100644 --- a/gestion/apps.py +++ b/gestion/apps.py @@ -6,7 +6,7 @@ class GestionConfig(AppConfig): verbose_name = "Gestion des outils communs COF/BDS" -def setup_assoc_perms(apps, assoc_getter, buro_of_apps=[], **kwargs): +def setup_assoc_perms(apps, assoc_getter, buro_of_apps=[], perms=[]): try: # Association and Permission models are required to be ready to setup # perms. @@ -14,4 +14,4 @@ def setup_assoc_perms(apps, assoc_getter, buro_of_apps=[], **kwargs): apps.get_app_config('auth') except LookupError: return - assoc_getter().setup_perms(buro_of_apps=buro_of_apps) + assoc_getter().setup_perms(buro_of_apps=buro_of_apps, perms=perms) diff --git a/gestion/models.py b/gestion/models.py index 893c21c2..dc6101ba 100644 --- a/gestion/models.py +++ b/gestion/models.py @@ -105,7 +105,7 @@ class Association(models.Model): def __str__(self): return self.name - def setup_perms(self, buro_of_apps=[]): + def setup_perms(self, buro_of_apps=[], perms=[]): """ Setup permissions of the staff and members groups. @@ -118,6 +118,7 @@ class Association(models.Model): Arguments buro_of_apps (list of 'app_label', optional) + perms (list of permission codes, optional) Should be used in receiver of 'post_migrate' signal, after permissions creation. @@ -134,10 +135,10 @@ class Association(models.Model): else: group.permissions.add(perm) - app_label = self.name.lower() + assoc_app_label = self.name.lower() # Buro group has perm '.buro'. - try_add_perm(self.staff_group, app_label, 'buro') + try_add_perm(self.staff_group, assoc_app_label, 'buro') # Add all permissions of applications given 'buro_of_apps'. apps_perms = Permission.objects.filter( @@ -145,8 +146,13 @@ class Association(models.Model): ) self.staff_group.permissions.add(*apps_perms) + # Add extra permissions from 'perms' + for perm in perms: + app_label, codename = perm.split('.', maxsplit=1) + try_add_perm(self.staff_group, app_label, codename) + # Members have perm '.member'. - try_add_perm(self.members_group, app_label, 'member') + try_add_perm(self.members_group, assoc_app_label, 'member') # --- diff --git a/gestion/tests.py b/gestion/tests.py index 755b4f3b..8cba796e 100644 --- a/gestion/tests.py +++ b/gestion/tests.py @@ -127,8 +127,9 @@ class AuthTest(TestCase): class AssociationTests(TestCase): def setUp(self): - self.gestion_p = Permission.objects.filter( - content_type__app_label='gestion', + self.custommail_p = Permission.objects.filter( + content_type__app_label="custommail", + codename__in=["add_custommail", "change_custommail"] ) def assertAllAppPerms(self, group, app_label): @@ -153,6 +154,10 @@ class AssociationTests(TestCase): self.assertAllAppPerms(cof_assoc.staff_group, 'cof') self.assertAllAppPerms(cof_assoc.staff_group, 'gestion') + # + some permissions in custommail + for p in self.custommail_p: + self.assertIn(p, cof_assoc.staff_group.permissions.all()) + # Check cof members group has 'cof.member' permission. member_perm = Permission.objects.get( content_type__app_label='cof', @@ -174,6 +179,10 @@ class AssociationTests(TestCase): self.assertAllAppPerms(bds_assoc.staff_group, 'bds') self.assertAllAppPerms(bds_assoc.staff_group, 'gestion') + # + some permissions in custommail + for p in self.custommail_p: + self.assertIn(p, bds_assoc.staff_group.permissions.all()) + # Check cof members group has 'bds.member' permission. member_perm = Permission.objects.get( content_type__app_label='bds',