From 00939566966641e40a6b16f875eb325a9011a5a6 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Fri, 21 Jul 2017 15:48:40 +0200 Subject: [PATCH 1/8] Add event-specific groups and signals --- event/signals.py | 19 +++++++++++++++++++ users/migrations/0001_initial.py | 25 +++++++++++++++++++++++++ users/migrations/__init__.py | 0 users/models.py | 9 ++++++++- 4 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 event/signals.py create mode 100644 users/migrations/0001_initial.py create mode 100644 users/migrations/__init__.py diff --git a/event/signals.py b/event/signals.py new file mode 100644 index 0000000..f942e3c --- /dev/null +++ b/event/signals.py @@ -0,0 +1,19 @@ +from django.dispatch import receiver +from django.db.models.signals import post_save +from event.models import Event +from shared.models import GEGroup + + +@receiver(post_save, sender=Event) +def create_groups_for_event(sender, **kwargs): + event, created = kwargs["instance"], kwargs["created"] + if created: + GEGroup.objects.create( + name="orga", + event=event + ) + + GEGroup.objects.create( + name="participants", + event=event, + ) diff --git a/users/migrations/0001_initial.py b/users/migrations/0001_initial.py new file mode 100644 index 0000000..2b464b1 --- /dev/null +++ b/users/migrations/0001_initial.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.3 on 2017-07-20 13:37 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('auth', '0008_alter_user_username_max_length'), + ] + + operations = [ + migrations.CreateModel( + name='GEGroup', + 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')), + ], + bases=('auth.group',), + ), + ] diff --git a/users/migrations/__init__.py b/users/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/users/models.py b/users/models.py index 85206e0..615d1b0 100644 --- a/users/models.py +++ b/users/models.py @@ -1,2 +1,9 @@ from django.db import models -from django.contrib.auth.models import User +from django.contrib.auth import get_user_model +from django.contrib.auth.models import Group + +User = get_user_model() + + +class GEGroup(Group): + pass From e499281a1da0f2443cc94b4277885b79beafe700 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Fri, 21 Jul 2017 20:24:09 +0200 Subject: [PATCH 2/8] Create permissions and signals --- equipment/models.py | 2 ++ evenementiel/settings/common.py | 6 ++++++ event/apps.py | 3 +++ event/models.py | 5 +++++ event/signals.py | 37 ++++++++++++++++++++++++++++++--- requirements.txt | 1 + 6 files changed, 51 insertions(+), 3 deletions(-) diff --git a/equipment/models.py b/equipment/models.py index 6498756..f8db97a 100644 --- a/equipment/models.py +++ b/equipment/models.py @@ -16,6 +16,7 @@ class Equipment(EventSpecificMixin, models.Model): related_name="equipment", through="EquipmentAttribution", ) + needs_event_permissions = True class Meta: verbose_name = _("matériel") @@ -30,6 +31,7 @@ class EquipmentAttribution(models.Model): activity = models.ForeignKey(Activity) amount = models.PositiveSmallIntegerField(_("quantité attribuée")) remarks = models.TextField(_("remarques concernant l'attribution")) + needs_event_permissions = True class Meta: verbose_name = _("attribution de matériel") diff --git a/evenementiel/settings/common.py b/evenementiel/settings/common.py index 5d291cb..85594e5 100644 --- a/evenementiel/settings/common.py +++ b/evenementiel/settings/common.py @@ -58,6 +58,7 @@ INSTALLED_APPS = [ 'channels', 'bootstrapform', 'widget_tweaks', + 'guardian', ] MIDDLEWARE_CLASSES = [ @@ -121,6 +122,11 @@ CHANNEL_LAYERS = { } } +AUTHENTICATION_BACKEND = ( + 'django.contrib.auth.backends.ModelBackend', + 'guardian.backends.ObjectPermissionBackend', +) + # Password validation # https://docs.djangoproject.com/en/1.9/ref/settings/#auth-password-validators AUTH_PASSWORD_VALIDATORS = [ diff --git a/event/apps.py b/event/apps.py index 13b1f16..7604a87 100644 --- a/event/apps.py +++ b/event/apps.py @@ -3,3 +3,6 @@ from django.apps import AppConfig class EventConfig(AppConfig): name = 'event' + + def ready(self): + from . import signals diff --git a/event/models.py b/event/models.py index 36dca46..83cd985 100644 --- a/event/models.py +++ b/event/models.py @@ -61,6 +61,7 @@ class Place(EventSpecificMixin, models.Model): max_length=200, ) description = models.TextField(blank=True) + needs_event_permissions = True class Meta: verbose_name = _("lieu") @@ -92,6 +93,7 @@ class ActivityTag(EventSpecificMixin, models.Model): validators=[color_regex], help_text=_("Rentrer une couleur en hexadécimal"), ) + needs_event_permissions = True class Meta: verbose_name = _("tag") @@ -152,6 +154,8 @@ class AbstractActivityTemplate(SubscriptionMixin, models.Model): class ActivityTemplate(AbstractActivityTemplate): + needs_event_permissions = True + class Meta: verbose_name = _("template activité") verbose_name_plural = _("templates activité") @@ -173,6 +177,7 @@ class Activity(AbstractActivityTemplate): beginning = models.DateTimeField(_("heure de début")) end = models.DateTimeField(_("heure de fin")) + needs_event_permissions = True def get_herited(self, attrname): inherited_fields = [f.name for f in ActivityTemplate._meta.get_fields()] diff --git a/event/signals.py b/event/signals.py index f942e3c..040fc37 100644 --- a/event/signals.py +++ b/event/signals.py @@ -1,19 +1,50 @@ from django.dispatch import receiver -from django.db.models.signals import post_save +from django.db.models.signals import post_save, post_migrate +from django.apps import apps +from django.contrib.contenttypes.models import ContentType +from django.contrib.auth.models import Permission from event.models import Event -from shared.models import GEGroup +from users.models import GEGroup +from guardian.shortcuts import assign_perm @receiver(post_save, sender=Event) def create_groups_for_event(sender, **kwargs): event, created = kwargs["instance"], kwargs["created"] if created: - GEGroup.objects.create( + orgas = GEGroup.objects.create( name="orga", event=event ) + for perm in Permission.objects.filter(codename__contains="event_"): + assign_perm(perm.codename, orgas, event) + GEGroup.objects.create( name="participants", event=event, ) + + +@receiver(post_migrate) +def create_event_permissions(sender, **kwargs): + + def event_specific_permissions(): + opes = ['Add', 'Change', 'Delete'] + models = [model.__name__.lower() for model in apps.get_models() + if getattr(model, 'needs_event_permissions', False)] + + return [ + ('event_{}_{}'.format(op.lower(), model), + '{} {} for event'.format(op, model)) + for op in opes + for model in models + ] + + content_type = ContentType.objects.get_for_model(Event) + for (code, verbose) in event_specific_permissions(): + Permission.objects.get_or_create( + name=verbose, + content_type=content_type, + codename=code + ) diff --git a/requirements.txt b/requirements.txt index 41fb065..021d4d8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,6 +7,7 @@ django-bootstrap-form==3.2.1 django-widget-tweaks django-notifications django-contrib-comments +django-guardian # Production specific daphne From e2d5e726cd65d5a5c9137b8fc3f8a3c222f6adaa Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Fri, 21 Jul 2017 20:56:49 +0200 Subject: [PATCH 3/8] Finish dj-guardian setup --- evenementiel/settings/common.py | 2 +- users/migrations/0001_initial.py | 9 +++++++-- users/models.py | 3 ++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/evenementiel/settings/common.py b/evenementiel/settings/common.py index 85594e5..c0d1655 100644 --- a/evenementiel/settings/common.py +++ b/evenementiel/settings/common.py @@ -122,7 +122,7 @@ CHANNEL_LAYERS = { } } -AUTHENTICATION_BACKEND = ( +AUTHENTICATION_BACKENDS = ( 'django.contrib.auth.backends.ModelBackend', 'guardian.backends.ObjectPermissionBackend', ) diff --git a/users/migrations/0001_initial.py b/users/migrations/0001_initial.py index 2b464b1..2bf662c 100644 --- a/users/migrations/0001_initial.py +++ b/users/migrations/0001_initial.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Generated by Django 1.11.3 on 2017-07-20 13:37 +# Generated by Django 1.11.3 on 2017-07-21 18:29 from __future__ import unicode_literals from django.db import migrations, models @@ -11,6 +11,7 @@ class Migration(migrations.Migration): initial = True dependencies = [ + ('event', '0001_initial'), ('auth', '0008_alter_user_username_max_length'), ] @@ -19,7 +20,11 @@ class Migration(migrations.Migration): name='GEGroup', 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')), + ('event', models.ForeignKey(blank=True, help_text="Si spécifié, l'instance du modèle est spécifique à l'évènement en question", null=True, on_delete=django.db.models.deletion.CASCADE, to='event.Event', verbose_name='évènement')), ], - bases=('auth.group',), + options={ + 'abstract': False, + }, + bases=('auth.group', models.Model), ), ] diff --git a/users/models.py b/users/models.py index 615d1b0..5b6a0ac 100644 --- a/users/models.py +++ b/users/models.py @@ -1,9 +1,10 @@ from django.db import models from django.contrib.auth import get_user_model from django.contrib.auth.models import Group +from event.models import EventSpecificMixin User = get_user_model() -class GEGroup(Group): +class GEGroup(EventSpecificMixin, Group): pass From 910d8fe9c094101e302d225b6c56e6d68f8bb0d2 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Fri, 21 Jul 2017 21:06:45 +0200 Subject: [PATCH 4/8] Simplify flag system --- equipment/models.py | 2 -- event/models.py | 6 ++---- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/equipment/models.py b/equipment/models.py index f8db97a..6498756 100644 --- a/equipment/models.py +++ b/equipment/models.py @@ -16,7 +16,6 @@ class Equipment(EventSpecificMixin, models.Model): related_name="equipment", through="EquipmentAttribution", ) - needs_event_permissions = True class Meta: verbose_name = _("matériel") @@ -31,7 +30,6 @@ class EquipmentAttribution(models.Model): activity = models.ForeignKey(Activity) amount = models.PositiveSmallIntegerField(_("quantité attribuée")) remarks = models.TextField(_("remarques concernant l'attribution")) - needs_event_permissions = True class Meta: verbose_name = _("attribution de matériel") diff --git a/event/models.py b/event/models.py index 83cd985..37a44d4 100644 --- a/event/models.py +++ b/event/models.py @@ -50,6 +50,7 @@ class EventSpecificMixin(models.Model): blank=True, null=True ) + needs_event_permissions = True class Meta: abstract = True @@ -61,7 +62,6 @@ class Place(EventSpecificMixin, models.Model): max_length=200, ) description = models.TextField(blank=True) - needs_event_permissions = True class Meta: verbose_name = _("lieu") @@ -93,7 +93,6 @@ class ActivityTag(EventSpecificMixin, models.Model): validators=[color_regex], help_text=_("Rentrer une couleur en hexadécimal"), ) - needs_event_permissions = True class Meta: verbose_name = _("tag") @@ -148,13 +147,13 @@ class AbstractActivityTemplate(SubscriptionMixin, models.Model): Place, blank=True, ) + needs_event_permissions = True class Meta: abstract = True class ActivityTemplate(AbstractActivityTemplate): - needs_event_permissions = True class Meta: verbose_name = _("template activité") @@ -177,7 +176,6 @@ class Activity(AbstractActivityTemplate): beginning = models.DateTimeField(_("heure de début")) end = models.DateTimeField(_("heure de fin")) - needs_event_permissions = True def get_herited(self, attrname): inherited_fields = [f.name for f in ActivityTemplate._meta.get_fields()] From 25df34e57ea1697cbee4d7b673b9c816e1ab383c Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Mon, 24 Jul 2017 15:30:16 +0200 Subject: [PATCH 5/8] Add filter to permissions --- event/signals.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/event/signals.py b/event/signals.py index 040fc37..98c62cc 100644 --- a/event/signals.py +++ b/event/signals.py @@ -17,7 +17,9 @@ def create_groups_for_event(sender, **kwargs): event=event ) - for perm in Permission.objects.filter(codename__contains="event_"): + for perm in Permission.objects.filter( + content_type=ContentType.objects.get_for_model(Event), + codename__contains="event_"): assign_perm(perm.codename, orgas, event) GEGroup.objects.create( From 0b1641a002162152897dbe1521af95b3d07b96bf Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Thu, 17 Aug 2017 15:10:46 +0200 Subject: [PATCH 6/8] Tests and group uniqueness --- communication/tests.py | 8 +++--- event/signals.py | 4 +-- event/tests.py | 61 +++++++++++++++++++++++++++++++++++++----- 3 files changed, 59 insertions(+), 14 deletions(-) diff --git a/communication/tests.py b/communication/tests.py index 800eac6..0fce8fd 100644 --- a/communication/tests.py +++ b/communication/tests.py @@ -28,10 +28,8 @@ class SubscriptionTest(TestCase): created_by=cls.root, created_at=timezone.now(), description="Ceci est un test", - beginning_date=timezone.now() - + timedelta(days=30), - ending_date=timezone.now() - + timedelta(days=31), + beginning_date=timezone.now() + timedelta(days=30), + ending_date=timezone.now() + timedelta(days=31), ) cls.groupsub = GroupSubscription.objects.create( content_object=cls.event, @@ -55,4 +53,4 @@ class SubscriptionTest(TestCase): def test_all_subs(self): self.assertSetEqual(set(self.event.get_all_subscribers()), - {self.user_true, self.user_group_true}) + {self.user_true, self.user_group_true}) diff --git a/event/signals.py b/event/signals.py index f711f39..edac92b 100644 --- a/event/signals.py +++ b/event/signals.py @@ -12,7 +12,7 @@ def create_groups_for_event(sender, **kwargs): event, created = kwargs["instance"], kwargs["created"] if created: orgas = EventGroup.objects.create( - name="orga", + name="{}_orgas".format(event.slug), event=event ) @@ -22,7 +22,7 @@ def create_groups_for_event(sender, **kwargs): assign_perm(perm.codename, orgas, event) EventGroup.objects.create( - name="participants", + name="{}_participants".format(event.slug), event=event, ) diff --git a/event/tests.py b/event/tests.py index 29c840f..cac64c8 100644 --- a/event/tests.py +++ b/event/tests.py @@ -1,10 +1,13 @@ from django.contrib.auth import get_user_model +from django.contrib.contenttypes.models import ContentType +from django.contrib.auth.models import Permission from django.core.exceptions import ValidationError from django.test import TestCase from datetime import timedelta from django.utils import timezone -from .models import Event, ActivityTemplate, Activity, Place, \ +from .models import Event, EventGroup, ActivityTemplate, Activity, Place, \ ActivityTag +from guardian.shortcuts import assign_perm User = get_user_model() @@ -24,10 +27,8 @@ class ActivityInheritanceTest(TestCase): created_by=cls.erkan, created_at=timezone.now(), description="La nuit c'est lol", - beginning_date=timezone.now() - + timedelta(days=30), - ending_date=timezone.now() - + timedelta(days=31), + beginning_date=timezone.now() + timedelta(days=30), + ending_date=timezone.now() + timedelta(days=31), ) cls.loge = Place.objects.create(name="Loge 45") cls.aqua = Place.objects.create(name="Aquarium") @@ -47,8 +48,7 @@ class ActivityInheritanceTest(TestCase): self.real_act = Activity.objects.create( parent=self.template_act, event=self.event, - beginning=timezone.now() - + timedelta(days=30), + beginning=timezone.now() + timedelta(days=30), end=timezone.now() + timedelta(days=30) + timedelta(hours=2), @@ -155,3 +155,50 @@ class ActivityTagColorTest(TestCase): ) with self.assertRaises(ValidationError): self.tag.full_clean() + + +class EventPermissionTest(TestCase): + @classmethod + def setUpTestData(cls): + cls.user_perm = User.objects.create(username="userperm") + cls.user_noperm = User.objects.create(username="usernoperm") + cls.user_groupperm = User.objects.create(username="usergroupperm") + cls.user_groupnoperm = User.objects.create(username="usergroupnoperm") + cls.root = User.objects.create_superuser( + username="root", + email="toto@toto.io", + password="toto" + ) + cls.event = Event.objects.create( + title="Hackathon", + slug="django", + created_by=cls.root, + description="Le code c'est cool", + beginning_date=timezone.now(), + ending_date=timezone.now() + timedelta(days=1), + ) + + def test_event_groups(self): + groups = EventGroup.objects.filter( + event=self.event + ) + self.assertEqual(groups.count(), 2) + + def test_individual_perms(self): + assign_perm("event_add_place", self.user_perm, self.event) + self.assertTrue(self.user_perm.has_perm("event_add_place", self.event)) + self.assertFalse(self.user_noperm.has_perm("event_add_place", + self.event)) + + def test_group_perms(self): + orgas = EventGroup.objects.get( + name="{}_orgas".format(self.event.slug), + ) + self.user_groupperm.groups.add(orgas) + for perm in Permission.objects.filter( + content_type=ContentType.objects.get_for_model(Event), + codename__contains="event_"): + self.assertTrue(self.user_groupperm.has_perm(perm.codename, + self.event)) + self.assertFalse(self.user_groupnoperm.has_perm(perm.codename, + self.event)) From c894d359324eab0c6fab607d6c4afe74fbc23dc2 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Tue, 19 Sep 2017 10:46:26 +0200 Subject: [PATCH 7/8] Scrap useless perms --- event/migrations/0003_auto_20170919_0845.py | 35 ++++++++++++++++++ event/models.py | 5 +++ event/signals.py | 41 ++++++--------------- event/tests.py | 39 ++++++++++++-------- 4 files changed, 76 insertions(+), 44 deletions(-) create mode 100644 event/migrations/0003_auto_20170919_0845.py diff --git a/event/migrations/0003_auto_20170919_0845.py b/event/migrations/0003_auto_20170919_0845.py new file mode 100644 index 0000000..69b9a20 --- /dev/null +++ b/event/migrations/0003_auto_20170919_0845.py @@ -0,0 +1,35 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.4 on 2017-09-19 08:45 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('event', '0002_auto_20170817_1221'), + ] + + operations = [ + migrations.AlterModelOptions( + name='activity', + options={'default_permissions': ('add', 'delete', 'change', 'view'), 'verbose_name': 'activité', 'verbose_name_plural': 'activités'}, + ), + migrations.AlterModelOptions( + name='activitytag', + options={'default_permissions': ('add', 'delete', 'change', 'view'), 'verbose_name': 'tag', 'verbose_name_plural': 'tags'}, + ), + migrations.AlterModelOptions( + name='activitytemplate', + options={'default_permissions': ('add', 'delete', 'change', 'view'), 'verbose_name': 'template activité', 'verbose_name_plural': 'templates activité'}, + ), + migrations.AlterModelOptions( + name='event', + options={'default_permissions': ('add', 'delete', 'change', 'view'), 'verbose_name': 'évènement', 'verbose_name_plural': 'évènements'}, + ), + migrations.AlterModelOptions( + name='place', + options={'default_permissions': ('add', 'delete', 'change', 'view'), 'verbose_name': 'lieu', 'verbose_name_plural': 'lieux'}, + ), + ] diff --git a/event/models.py b/event/models.py index c328688..76af063 100644 --- a/event/models.py +++ b/event/models.py @@ -47,6 +47,7 @@ class Event(SubscriptionMixin, models.Model): class Meta: verbose_name = _("évènement") verbose_name_plural = _("évènements") + default_permissions = ('add', 'delete', 'change', 'view') def __str__(self): return self.title @@ -86,6 +87,7 @@ class Place(EventSpecificMixin, models.Model): class Meta: verbose_name = _("lieu") verbose_name_plural = _("lieux") + default_permissions = ('add', 'delete', 'change', 'view') def __str__(self): return self.name @@ -113,6 +115,7 @@ class ActivityTag(EventSpecificMixin, models.Model): class Meta: verbose_name = _("tag") verbose_name_plural = _("tags") + default_permissions = ('add', 'delete', 'change', 'view') def __str__(self): return self.name @@ -178,6 +181,7 @@ class ActivityTemplate(AbstractActivityTemplate): class Meta: verbose_name = _("template activité") verbose_name_plural = _("templates activité") + default_permissions = ('add', 'delete', 'change', 'view') def __str__(self): return self.title @@ -225,6 +229,7 @@ class Activity(AbstractActivityTemplate): class Meta: verbose_name = _("activité") verbose_name_plural = _("activités") + default_permissions = ('add', 'delete', 'change', 'view') def __str__(self): return self.get_herited('title') diff --git a/event/signals.py b/event/signals.py index edac92b..e601e9a 100644 --- a/event/signals.py +++ b/event/signals.py @@ -1,5 +1,5 @@ from django.dispatch import receiver -from django.db.models.signals import post_save, post_migrate +from django.db.models.signals import post_save from django.apps import apps from django.contrib.contenttypes.models import ContentType from django.contrib.auth.models import Permission @@ -16,36 +16,19 @@ def create_groups_for_event(sender, **kwargs): event=event ) - for perm in Permission.objects.filter( - content_type=ContentType.objects.get_for_model(Event), - codename__contains="event_"): - assign_perm(perm.codename, orgas, event) + # Models having event-specific permissions + models = [model for model in apps.get_models() + if getattr(model, 'needs_event_permissions', False)] + + for model in models: + + for perm in Permission.objects.filter( + content_type=ContentType.objects.get_for_model(model) + ): + print(perm.codename) + assign_perm(perm.codename, orgas, event) EventGroup.objects.create( name="{}_participants".format(event.slug), event=event, ) - - -@receiver(post_migrate) -def create_event_permissions(sender, **kwargs): - - def event_specific_permissions(): - opes = ['Add', 'Change', 'Delete'] - models = [model.__name__.lower() for model in apps.get_models() - if getattr(model, 'needs_event_permissions', False)] - - return [ - ('event_{}_{}'.format(op.lower(), model), - '{} {} for event'.format(op, model)) - for op in opes - for model in models - ] - - content_type = ContentType.objects.get_for_model(Event) - for (code, verbose) in event_specific_permissions(): - Permission.objects.get_or_create( - name=verbose, - content_type=content_type, - codename=code - ) diff --git a/event/tests.py b/event/tests.py index cac64c8..b6eaa5c 100644 --- a/event/tests.py +++ b/event/tests.py @@ -160,10 +160,6 @@ class ActivityTagColorTest(TestCase): class EventPermissionTest(TestCase): @classmethod def setUpTestData(cls): - cls.user_perm = User.objects.create(username="userperm") - cls.user_noperm = User.objects.create(username="usernoperm") - cls.user_groupperm = User.objects.create(username="usergroupperm") - cls.user_groupnoperm = User.objects.create(username="usergroupnoperm") cls.root = User.objects.create_superuser( username="root", email="toto@toto.io", @@ -178,6 +174,21 @@ class EventPermissionTest(TestCase): ending_date=timezone.now() + timedelta(days=1), ) + models = [model for model in apps.get_models() + if getattr(model, 'needs_event_permissions', False)] + + cls.perms = [] + for model in models: + + for perm in Permission.objects.filter( + content_type=ContentType.objects.get_for_model(model) + ): + cls.perms.append(perm.codename) + + def setUp(self): + self.user_perm = User.objects.create(username="userperm") + self.user_noperm = User.objects.create(username="usernoperm") + def test_event_groups(self): groups = EventGroup.objects.filter( event=self.event @@ -185,20 +196,18 @@ class EventPermissionTest(TestCase): self.assertEqual(groups.count(), 2) def test_individual_perms(self): - assign_perm("event_add_place", self.user_perm, self.event) - self.assertTrue(self.user_perm.has_perm("event_add_place", self.event)) - self.assertFalse(self.user_noperm.has_perm("event_add_place", - self.event)) + for perm in self.perms: + assign_perm(perm, self.user_perm, self.event) + self.assertTrue(self.user_perm.has_perm(perm, self.event)) + self.assertFalse(self.user_noperm.has_perm(perm, self.event)) def test_group_perms(self): orgas = EventGroup.objects.get( name="{}_orgas".format(self.event.slug), ) self.user_groupperm.groups.add(orgas) - for perm in Permission.objects.filter( - content_type=ContentType.objects.get_for_model(Event), - codename__contains="event_"): - self.assertTrue(self.user_groupperm.has_perm(perm.codename, - self.event)) - self.assertFalse(self.user_groupnoperm.has_perm(perm.codename, - self.event)) + for perm in self.perms: + self.assertTrue(self.user_perm.has_perm(perm, + self.event)) + self.assertFalse(self.user_noperm.has_perm(perm, + self.event)) From 392e5cf14477a2ecb484e34f8c2261f2421f1d08 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Tue, 19 Sep 2017 11:48:39 +0200 Subject: [PATCH 8/8] Revert c894d35 --- Fuck django-guardian This reverts commit c894d359324eab0c6fab607d6c4afe74fbc23dc2. --- event/migrations/0003_auto_20170919_0845.py | 35 ------------------ event/models.py | 5 --- event/signals.py | 41 +++++++++++++++------ event/tests.py | 39 ++++++++------------ 4 files changed, 44 insertions(+), 76 deletions(-) delete mode 100644 event/migrations/0003_auto_20170919_0845.py diff --git a/event/migrations/0003_auto_20170919_0845.py b/event/migrations/0003_auto_20170919_0845.py deleted file mode 100644 index 69b9a20..0000000 --- a/event/migrations/0003_auto_20170919_0845.py +++ /dev/null @@ -1,35 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.11.4 on 2017-09-19 08:45 -from __future__ import unicode_literals - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('event', '0002_auto_20170817_1221'), - ] - - operations = [ - migrations.AlterModelOptions( - name='activity', - options={'default_permissions': ('add', 'delete', 'change', 'view'), 'verbose_name': 'activité', 'verbose_name_plural': 'activités'}, - ), - migrations.AlterModelOptions( - name='activitytag', - options={'default_permissions': ('add', 'delete', 'change', 'view'), 'verbose_name': 'tag', 'verbose_name_plural': 'tags'}, - ), - migrations.AlterModelOptions( - name='activitytemplate', - options={'default_permissions': ('add', 'delete', 'change', 'view'), 'verbose_name': 'template activité', 'verbose_name_plural': 'templates activité'}, - ), - migrations.AlterModelOptions( - name='event', - options={'default_permissions': ('add', 'delete', 'change', 'view'), 'verbose_name': 'évènement', 'verbose_name_plural': 'évènements'}, - ), - migrations.AlterModelOptions( - name='place', - options={'default_permissions': ('add', 'delete', 'change', 'view'), 'verbose_name': 'lieu', 'verbose_name_plural': 'lieux'}, - ), - ] diff --git a/event/models.py b/event/models.py index 76af063..c328688 100644 --- a/event/models.py +++ b/event/models.py @@ -47,7 +47,6 @@ class Event(SubscriptionMixin, models.Model): class Meta: verbose_name = _("évènement") verbose_name_plural = _("évènements") - default_permissions = ('add', 'delete', 'change', 'view') def __str__(self): return self.title @@ -87,7 +86,6 @@ class Place(EventSpecificMixin, models.Model): class Meta: verbose_name = _("lieu") verbose_name_plural = _("lieux") - default_permissions = ('add', 'delete', 'change', 'view') def __str__(self): return self.name @@ -115,7 +113,6 @@ class ActivityTag(EventSpecificMixin, models.Model): class Meta: verbose_name = _("tag") verbose_name_plural = _("tags") - default_permissions = ('add', 'delete', 'change', 'view') def __str__(self): return self.name @@ -181,7 +178,6 @@ class ActivityTemplate(AbstractActivityTemplate): class Meta: verbose_name = _("template activité") verbose_name_plural = _("templates activité") - default_permissions = ('add', 'delete', 'change', 'view') def __str__(self): return self.title @@ -229,7 +225,6 @@ class Activity(AbstractActivityTemplate): class Meta: verbose_name = _("activité") verbose_name_plural = _("activités") - default_permissions = ('add', 'delete', 'change', 'view') def __str__(self): return self.get_herited('title') diff --git a/event/signals.py b/event/signals.py index e601e9a..edac92b 100644 --- a/event/signals.py +++ b/event/signals.py @@ -1,5 +1,5 @@ from django.dispatch import receiver -from django.db.models.signals import post_save +from django.db.models.signals import post_save, post_migrate from django.apps import apps from django.contrib.contenttypes.models import ContentType from django.contrib.auth.models import Permission @@ -16,19 +16,36 @@ def create_groups_for_event(sender, **kwargs): event=event ) - # Models having event-specific permissions - models = [model for model in apps.get_models() - if getattr(model, 'needs_event_permissions', False)] - - for model in models: - - for perm in Permission.objects.filter( - content_type=ContentType.objects.get_for_model(model) - ): - print(perm.codename) - assign_perm(perm.codename, orgas, event) + for perm in Permission.objects.filter( + content_type=ContentType.objects.get_for_model(Event), + codename__contains="event_"): + assign_perm(perm.codename, orgas, event) EventGroup.objects.create( name="{}_participants".format(event.slug), event=event, ) + + +@receiver(post_migrate) +def create_event_permissions(sender, **kwargs): + + def event_specific_permissions(): + opes = ['Add', 'Change', 'Delete'] + models = [model.__name__.lower() for model in apps.get_models() + if getattr(model, 'needs_event_permissions', False)] + + return [ + ('event_{}_{}'.format(op.lower(), model), + '{} {} for event'.format(op, model)) + for op in opes + for model in models + ] + + content_type = ContentType.objects.get_for_model(Event) + for (code, verbose) in event_specific_permissions(): + Permission.objects.get_or_create( + name=verbose, + content_type=content_type, + codename=code + ) diff --git a/event/tests.py b/event/tests.py index b6eaa5c..cac64c8 100644 --- a/event/tests.py +++ b/event/tests.py @@ -160,6 +160,10 @@ class ActivityTagColorTest(TestCase): class EventPermissionTest(TestCase): @classmethod def setUpTestData(cls): + cls.user_perm = User.objects.create(username="userperm") + cls.user_noperm = User.objects.create(username="usernoperm") + cls.user_groupperm = User.objects.create(username="usergroupperm") + cls.user_groupnoperm = User.objects.create(username="usergroupnoperm") cls.root = User.objects.create_superuser( username="root", email="toto@toto.io", @@ -174,21 +178,6 @@ class EventPermissionTest(TestCase): ending_date=timezone.now() + timedelta(days=1), ) - models = [model for model in apps.get_models() - if getattr(model, 'needs_event_permissions', False)] - - cls.perms = [] - for model in models: - - for perm in Permission.objects.filter( - content_type=ContentType.objects.get_for_model(model) - ): - cls.perms.append(perm.codename) - - def setUp(self): - self.user_perm = User.objects.create(username="userperm") - self.user_noperm = User.objects.create(username="usernoperm") - def test_event_groups(self): groups = EventGroup.objects.filter( event=self.event @@ -196,18 +185,20 @@ class EventPermissionTest(TestCase): self.assertEqual(groups.count(), 2) def test_individual_perms(self): - for perm in self.perms: - assign_perm(perm, self.user_perm, self.event) - self.assertTrue(self.user_perm.has_perm(perm, self.event)) - self.assertFalse(self.user_noperm.has_perm(perm, self.event)) + assign_perm("event_add_place", self.user_perm, self.event) + self.assertTrue(self.user_perm.has_perm("event_add_place", self.event)) + self.assertFalse(self.user_noperm.has_perm("event_add_place", + self.event)) def test_group_perms(self): orgas = EventGroup.objects.get( name="{}_orgas".format(self.event.slug), ) self.user_groupperm.groups.add(orgas) - for perm in self.perms: - self.assertTrue(self.user_perm.has_perm(perm, - self.event)) - self.assertFalse(self.user_noperm.has_perm(perm, - self.event)) + for perm in Permission.objects.filter( + content_type=ContentType.objects.get_for_model(Event), + codename__contains="event_"): + self.assertTrue(self.user_groupperm.has_perm(perm.codename, + self.event)) + self.assertFalse(self.user_groupnoperm.has_perm(perm.codename, + self.event))