From b0afa0fd86faec0bd44cbc429b9ef74ee0afd5e5 Mon Sep 17 00:00:00 2001 From: Christophe Siraut Date: Wed, 18 Oct 2023 15:44:47 +0200 Subject: [PATCH] models/program: link to editor groups --- aircox/migrations/0015_program_editors.py | 25 ++++++++++++++++++++++ aircox/models/program.py | 26 +++++++++++++++++++++++ aircox/tests/test_permissions.py | 11 ++++++++++ 3 files changed, 62 insertions(+) create mode 100644 aircox/migrations/0015_program_editors.py diff --git a/aircox/migrations/0015_program_editors.py b/aircox/migrations/0015_program_editors.py new file mode 100644 index 0000000..9a3964f --- /dev/null +++ b/aircox/migrations/0015_program_editors.py @@ -0,0 +1,25 @@ +# Generated by Django 4.2.5 on 2023-10-18 13:50 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + dependencies = [ + ("auth", "0012_alter_user_first_name_max_length"), + ("aircox", "0014_alter_schedule_timezone"), + ] + + operations = [ + migrations.AddField( + model_name="program", + name="editors", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="auth.group", + verbose_name="editors", + ), + ), + ] diff --git a/aircox/models/program.py b/aircox/models/program.py index 7a4fd16..7a6e6f3 100644 --- a/aircox/models/program.py +++ b/aircox/models/program.py @@ -3,6 +3,8 @@ import os import shutil from django.conf import settings as conf +from django.contrib.auth.models import Group, Permission +from django.contrib.contenttypes.models import ContentType from django.db import models from django.db.models import F from django.db.models.functions import Concat, Substr @@ -58,6 +60,7 @@ class Program(Page): default=True, help_text=_("update later diffusions according to schedule changes"), ) + editors = models.ForeignKey(Group, models.CASCADE, blank=True, null=True, verbose_name=_("editors")) objects = ProgramQuerySet.as_manager() detail_url_name = "program-detail" @@ -80,6 +83,14 @@ class Program(Page): def excerpts_path(self): return os.path.join(self.path, settings.SOUND_ARCHIVES_SUBDIR) + @property + def editors_group_name(self): + return f"{self.title} editors" + + @property + def change_permission_codename(self): + return f"change_program_{self.slug}" + def __init__(self, *kargs, **kwargs): super().__init__(*kargs, **kwargs) if self.slug: @@ -109,6 +120,18 @@ class Program(Page): os.makedirs(path, exist_ok=True) return os.path.exists(path) + def set_group_ownership(self): + editors, created = Group.objects.get_or_create(name=self.editors_group_name) + if created: + self.editors = editors + permission, _ = Permission.objects.get_or_create( + name=f"change program {self.title}", + codename=self.change_permission_codename, + content_type=ContentType.objects.get_for_model(self), + ) + if permission not in editors.permissions.all(): + editors.permissions.add(permission) + class Meta: verbose_name = _("Program") verbose_name_plural = _("Programs") @@ -134,6 +157,9 @@ class Program(Page): shutil.move(abspath, self.abspath) Sound.objects.filter(path__startswith=path_).update(file=Concat("file", Substr(F("file"), len(path_)))) + self.set_group_ownership() + super().save(*kargs, **kwargs) + class ProgramChildQuerySet(PageQuerySet): def station(self, station=None, id=None): diff --git a/aircox/tests/test_permissions.py b/aircox/tests/test_permissions.py index 54bf67a..25866b3 100644 --- a/aircox/tests/test_permissions.py +++ b/aircox/tests/test_permissions.py @@ -1,4 +1,5 @@ import pytest +from django.contrib.auth.models import User, Group @pytest.mark.django_db() @@ -12,3 +13,13 @@ def test_no_admin(user, client): def test_user_cannot_change_program_or_episode(user, client, program): assert not user.has_perm("aircox.change_program") assert not user.has_perm("aircox.change_episode") + + +@pytest.mark.django_db() +def test_group_can_change_program(user, client, program): + assert program.editors in Group.objects.all() + assert not user.has_perm("aircox.%s" % program.change_permission_codename) + user.groups.add(program.editors) + user = User.objects.get(pk=user.pk) # reload user in order to have permissions set + assert program.editors in user.groups.all() + assert user.has_perm("aircox.%s" % program.change_permission_codename)