diff --git a/babybuddy/apps.py b/babybuddy/apps.py index 61161b69..2e9775f2 100644 --- a/babybuddy/apps.py +++ b/babybuddy/apps.py @@ -2,10 +2,18 @@ import os from django.apps import AppConfig +from django.conf import settings +from django.db.models.signals import post_migrate from babybuddy import VERSION +def create_read_only_group(sender, **kwargs): + from django.contrib.auth.models import Group + + Group.objects.get_or_create(name=settings.BABY_BUDDY["READ_ONLY_GROUP_NAME"]) + + class BabyBuddyConfig(AppConfig): name = "babybuddy" verbose_name = "Baby Buddy" @@ -16,3 +24,4 @@ class BabyBuddyConfig(AppConfig): if os.path.isfile(".git/refs/heads/master"): commit = open(".git/refs/heads/master").read() self.version_string += " ({})".format(commit[0:7]) + post_migrate.connect(create_read_only_group, sender=self) diff --git a/babybuddy/forms.py b/babybuddy/forms.py index ceec15ae..5fb82d60 100644 --- a/babybuddy/forms.py +++ b/babybuddy/forms.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- from django import forms +from django.conf import settings from django.contrib.auth import get_user_model from django.contrib.auth.forms import PasswordChangeForm, UserCreationForm from django.contrib.auth.models import Group @@ -31,7 +32,11 @@ class BabyBuddyUserForm(forms.ModelForm): user = kwargs["instance"] if user: kwargs["initial"].update( - {"is_read_only": user.groups.filter(name="read_only").exists()} + { + "is_read_only": user.groups.filter( + name=settings.BABY_BUDDY["READ_ONLY_GROUP_NAME"] + ).exists() + } ) super(BabyBuddyUserForm, self).__init__(*args, **kwargs) @@ -44,7 +49,9 @@ class BabyBuddyUserForm(forms.ModelForm): user.is_superuser = True if commit: user.save() - readonly_group = Group.objects.get(name="read_only") + readonly_group = Group.objects.get( + name=settings.BABY_BUDDY["READ_ONLY_GROUP_NAME"] + ) if is_read_only: user.groups.add(readonly_group.id) else: diff --git a/babybuddy/management/commands/createuser.py b/babybuddy/management/commands/createuser.py index cd3641a5..27c492e6 100644 --- a/babybuddy/management/commands/createuser.py +++ b/babybuddy/management/commands/createuser.py @@ -11,6 +11,7 @@ Example usage: import sys import getpass +from django.conf import settings from django.contrib.auth import get_user_model, models from django.contrib.auth.password_validation import validate_password from django.core import exceptions @@ -119,7 +120,9 @@ class Command(BaseCommand): if is_read_only: user.is_superuser = False user.save() - group = models.Group.objects.get(name="read_only") + group = models.Group.objects.get( + name=settings.BABY_BUDDY["READ_ONLY_GROUP_NAME"] + ) user.groups.add(group) else: user.is_superuser = True diff --git a/babybuddy/migrations/0025_auto_20221023_0821.py b/babybuddy/migrations/0025_auto_20221023_0821.py index 8c45af3e..75d2c926 100644 --- a/babybuddy/migrations/0025_auto_20221023_0821.py +++ b/babybuddy/migrations/0025_auto_20221023_0821.py @@ -1,72 +1,6 @@ # Generated by Django 4.1.2 on 2022-10-23 08:21 from django.db import migrations -from django.contrib.auth.models import Group, Permission -import logging - - -logger = logging.getLogger(__name__) - -# MODELS = [model.__name__ for model in apps.get_models()] -MODELS = [ - "Tag", - "tagged", - "BMI", - "Child", - "Diaper Change", - "Feeding", - "Head Circumference", - "Height", - "Note", - "Pumping", - "Sleep", - "Temperature", - "Timer", - "Tummy Time", - "Weight", - "user", -] -PERMISSIONS = ["add", "change", "delete", "view"] - - -def add_group_permissions(apps, schema_editor): - group, created = Group.objects.get_or_create(name="read_only") - perm = [] - for model in MODELS: - name = f"Can view {model}" - logging.info(f"Creating {name}...") - - try: - perm.append(Permission.objects.get(name=name)) - except Permission.DoesNotExist: - logging.warning(f"Permission not found with name {name}.") - continue - - group.permissions.add(*perm) - - group, created = Group.objects.get_or_create(name="standard") - perm = [] - for model in MODELS: - for permission in PERMISSIONS: - name = f"Can {permission} {model}" - logging.info(f"Creating {name}...") - - try: - perm.append(Permission.objects.get(name=name)) - except Permission.DoesNotExist: - logging.warning(f"Permission not found with name {name}.") - continue - - group.permissions.add(*perm) - - -def revert_migration(apps, schema_editor): - Group.objects.filter( - name__in=[ - "read_only", - "standard", - ] - ).delete() class Migration(migrations.Migration): @@ -74,4 +8,5 @@ class Migration(migrations.Migration): ("babybuddy", "0023_alter_settings_timezone"), ] - operations = [migrations.RunPython(add_group_permissions, revert_migration)] + # Migration removed in favor of post migrate handling in core.apps.CoreConfig. + operations = [] diff --git a/babybuddy/settings/base.py b/babybuddy/settings/base.py index f8686ad9..82cce703 100644 --- a/babybuddy/settings/base.py +++ b/babybuddy/settings/base.py @@ -24,8 +24,8 @@ DEBUG = bool(strtobool(os.environ.get("DEBUG") or "False")) INSTALLED_APPS = [ "api", - "babybuddy", - "core", + "babybuddy.apps.BabyBuddyConfig", + "core.apps.CoreConfig", "dashboard", "reports", "axes", @@ -356,7 +356,8 @@ DEFAULT_AUTO_FIELD = "django.db.models.AutoField" # See README.md#configuration for details about these settings. BABY_BUDDY = { - "NAP_START_MIN": os.environ.get("NAP_START_MIN") or "06:00", - "NAP_START_MAX": os.environ.get("NAP_START_MAX") or "18:00", "ALLOW_UPLOADS": bool(strtobool(os.environ.get("ALLOW_UPLOADS") or "True")), + "NAP_START_MAX": os.environ.get("NAP_START_MAX") or "18:00", + "NAP_START_MIN": os.environ.get("NAP_START_MIN") or "06:00", + "READ_ONLY_GROUP_NAME": "read_only", } diff --git a/babybuddy/templatetags/babybuddy.py b/babybuddy/templatetags/babybuddy.py index eeaf1575..df2ad667 100644 --- a/babybuddy/templatetags/babybuddy.py +++ b/babybuddy/templatetags/babybuddy.py @@ -2,6 +2,7 @@ from django import template from django.apps import apps +from django.conf import settings from django.utils import timezone from django.utils.translation import to_locale, get_language @@ -80,4 +81,4 @@ def user_is_locked(user): @register.simple_tag() def user_is_read_only(user): - return user.groups.filter(name="read_only").exists() + return user.groups.filter(name=settings.BABY_BUDDY["READ_ONLY_GROUP_NAME"]).exists() diff --git a/babybuddy/tests/tests_commands.py b/babybuddy/tests/tests_commands.py index fec1ec5e..1939e923 100644 --- a/babybuddy/tests/tests_commands.py +++ b/babybuddy/tests/tests_commands.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- from django.test import TransactionTestCase +from django.conf import settings from django.contrib.auth import get_user_model from django.core.management import call_command @@ -28,6 +29,7 @@ class CommandsTestCase(TransactionTestCase): self.assertEqual(Child.objects.count(), 1) def test_createuser(self): + call_command("migrate", verbosity=0) call_command( "createuser", username="regularuser", @@ -66,4 +68,8 @@ class CommandsTestCase(TransactionTestCase): self.assertIsInstance(user, get_user_model()) self.assertFalse(user.is_superuser) self.assertFalse(user.is_staff) - self.assertTrue(user.groups.filter(name="read_only").exists()) + self.assertTrue( + user.groups.filter( + name=settings.BABY_BUDDY["READ_ONLY_GROUP_NAME"] + ).exists() + ) diff --git a/babybuddy/tests/tests_forms.py b/babybuddy/tests/tests_forms.py index 91aeeb19..457436dd 100644 --- a/babybuddy/tests/tests_forms.py +++ b/babybuddy/tests/tests_forms.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- import datetime +from django.conf import settings from django.contrib.auth import get_user_model from django.core.management import call_command from django.test import Client as HttpClient, override_settings, TestCase @@ -117,7 +118,11 @@ class FormsTestCase(TestCase): self.assertIsInstance(user, get_user_model()) self.assertTrue(user.is_superuser) self.assertFalse(user.is_staff) - self.assertFalse(user.groups.filter(name="read_only").exists()) + self.assertFalse( + user.groups.filter( + name=settings.BABY_BUDDY["READ_ONLY_GROUP_NAME"] + ).exists() + ) def test_add_staff_user(self): self.user.is_staff = True @@ -133,7 +138,11 @@ class FormsTestCase(TestCase): self.assertIsInstance(user, get_user_model()) self.assertTrue(user.is_superuser) self.assertTrue(user.is_staff) - self.assertFalse(user.groups.filter(name="read_only").exists()) + self.assertFalse( + user.groups.filter( + name=settings.BABY_BUDDY["READ_ONLY_GROUP_NAME"] + ).exists() + ) def test_add_read_only_user(self): self.user.is_staff = True @@ -149,7 +158,11 @@ class FormsTestCase(TestCase): self.assertIsInstance(user, get_user_model()) self.assertFalse(user.is_superuser) self.assertFalse(user.is_staff) - self.assertTrue(user.groups.filter(name="read_only").exists()) + self.assertTrue( + user.groups.filter( + name=settings.BABY_BUDDY["READ_ONLY_GROUP_NAME"] + ).exists() + ) def test_user_settings(self): self.c.login(**self.credentials) diff --git a/babybuddy/tests/tests_templatetags.py b/babybuddy/tests/tests_templatetags.py index 2bfbf3ab..20cae704 100644 --- a/babybuddy/tests/tests_templatetags.py +++ b/babybuddy/tests/tests_templatetags.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +from django.conf import settings from django.contrib.auth import get_user_model from django.contrib.auth.models import Group from django.test import TestCase @@ -26,6 +27,6 @@ class TemplateTagsTestCase(TestCase): ) self.assertFalse(babybuddy.user_is_read_only(user)) - group = Group.objects.get(name="read_only") + group = Group.objects.get(name=settings.BABY_BUDDY["READ_ONLY_GROUP_NAME"]) user.groups.add(group) self.assertTrue(babybuddy.user_is_read_only(user)) diff --git a/core/apps.py b/core/apps.py new file mode 100644 index 00000000..d7f24649 --- /dev/null +++ b/core/apps.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +from django.apps import AppConfig +from django.conf import settings +from django.db.models.signals import post_migrate + + +def add_read_only_group_permissions(sender, **kwargs): + from django.apps import apps + from django.contrib.auth.models import Group, Permission + + permissions = [] + for model in apps.all_models["core"]: + try: + permissions.append(Permission.objects.get(codename=f"view_{model}")) + except Permission.DoesNotExist: + continue + + if len(permissions) > 0: + try: + group = Group.objects.get(name=settings.BABY_BUDDY["READ_ONLY_GROUP_NAME"]) + group.permissions.add(*permissions) + except Group.DoesNotExist: + pass + + +class CoreConfig(AppConfig): + name = "core" + + def ready(self): + post_migrate.connect(add_read_only_group_permissions, sender=self)