Refactor read only group creation as post migrate operation

This commit is contained in:
Christopher C. Wells 2023-02-11 10:31:14 -08:00
parent 996d81966c
commit 10a58e61b5
10 changed files with 86 additions and 80 deletions

View File

@ -2,10 +2,18 @@
import os import os
from django.apps import AppConfig from django.apps import AppConfig
from django.conf import settings
from django.db.models.signals import post_migrate
from babybuddy import VERSION 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): class BabyBuddyConfig(AppConfig):
name = "babybuddy" name = "babybuddy"
verbose_name = "Baby Buddy" verbose_name = "Baby Buddy"
@ -16,3 +24,4 @@ class BabyBuddyConfig(AppConfig):
if os.path.isfile(".git/refs/heads/master"): if os.path.isfile(".git/refs/heads/master"):
commit = open(".git/refs/heads/master").read() commit = open(".git/refs/heads/master").read()
self.version_string += " ({})".format(commit[0:7]) self.version_string += " ({})".format(commit[0:7])
post_migrate.connect(create_read_only_group, sender=self)

View File

@ -1,5 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from django import forms from django import forms
from django.conf import settings
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.contrib.auth.forms import PasswordChangeForm, UserCreationForm from django.contrib.auth.forms import PasswordChangeForm, UserCreationForm
from django.contrib.auth.models import Group from django.contrib.auth.models import Group
@ -31,7 +32,11 @@ class BabyBuddyUserForm(forms.ModelForm):
user = kwargs["instance"] user = kwargs["instance"]
if user: if user:
kwargs["initial"].update( 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) super(BabyBuddyUserForm, self).__init__(*args, **kwargs)
@ -44,7 +49,9 @@ class BabyBuddyUserForm(forms.ModelForm):
user.is_superuser = True user.is_superuser = True
if commit: if commit:
user.save() 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: if is_read_only:
user.groups.add(readonly_group.id) user.groups.add(readonly_group.id)
else: else:

View File

@ -11,6 +11,7 @@ Example usage:
import sys import sys
import getpass import getpass
from django.conf import settings
from django.contrib.auth import get_user_model, models from django.contrib.auth import get_user_model, models
from django.contrib.auth.password_validation import validate_password from django.contrib.auth.password_validation import validate_password
from django.core import exceptions from django.core import exceptions
@ -119,7 +120,9 @@ class Command(BaseCommand):
if is_read_only: if is_read_only:
user.is_superuser = False user.is_superuser = False
user.save() 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) user.groups.add(group)
else: else:
user.is_superuser = True user.is_superuser = True

View File

@ -1,72 +1,6 @@
# Generated by Django 4.1.2 on 2022-10-23 08:21 # Generated by Django 4.1.2 on 2022-10-23 08:21
from django.db import migrations 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): class Migration(migrations.Migration):
@ -74,4 +8,5 @@ class Migration(migrations.Migration):
("babybuddy", "0023_alter_settings_timezone"), ("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 = []

View File

@ -24,8 +24,8 @@ DEBUG = bool(strtobool(os.environ.get("DEBUG") or "False"))
INSTALLED_APPS = [ INSTALLED_APPS = [
"api", "api",
"babybuddy", "babybuddy.apps.BabyBuddyConfig",
"core", "core.apps.CoreConfig",
"dashboard", "dashboard",
"reports", "reports",
"axes", "axes",
@ -356,7 +356,8 @@ DEFAULT_AUTO_FIELD = "django.db.models.AutoField"
# See README.md#configuration for details about these settings. # See README.md#configuration for details about these settings.
BABY_BUDDY = { 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")), "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",
} }

View File

@ -2,6 +2,7 @@
from django import template from django import template
from django.apps import apps from django.apps import apps
from django.conf import settings
from django.utils import timezone from django.utils import timezone
from django.utils.translation import to_locale, get_language from django.utils.translation import to_locale, get_language
@ -80,4 +81,4 @@ def user_is_locked(user):
@register.simple_tag() @register.simple_tag()
def user_is_read_only(user): 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()

View File

@ -1,5 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from django.test import TransactionTestCase from django.test import TransactionTestCase
from django.conf import settings
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.core.management import call_command from django.core.management import call_command
@ -28,6 +29,7 @@ class CommandsTestCase(TransactionTestCase):
self.assertEqual(Child.objects.count(), 1) self.assertEqual(Child.objects.count(), 1)
def test_createuser(self): def test_createuser(self):
call_command("migrate", verbosity=0)
call_command( call_command(
"createuser", "createuser",
username="regularuser", username="regularuser",
@ -66,4 +68,8 @@ class CommandsTestCase(TransactionTestCase):
self.assertIsInstance(user, get_user_model()) self.assertIsInstance(user, get_user_model())
self.assertFalse(user.is_superuser) self.assertFalse(user.is_superuser)
self.assertFalse(user.is_staff) 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()
)

View File

@ -1,6 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import datetime import datetime
from django.conf import settings
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.core.management import call_command from django.core.management import call_command
from django.test import Client as HttpClient, override_settings, TestCase from django.test import Client as HttpClient, override_settings, TestCase
@ -117,7 +118,11 @@ class FormsTestCase(TestCase):
self.assertIsInstance(user, get_user_model()) self.assertIsInstance(user, get_user_model())
self.assertTrue(user.is_superuser) self.assertTrue(user.is_superuser)
self.assertFalse(user.is_staff) 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): def test_add_staff_user(self):
self.user.is_staff = True self.user.is_staff = True
@ -133,7 +138,11 @@ class FormsTestCase(TestCase):
self.assertIsInstance(user, get_user_model()) self.assertIsInstance(user, get_user_model())
self.assertTrue(user.is_superuser) self.assertTrue(user.is_superuser)
self.assertTrue(user.is_staff) 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): def test_add_read_only_user(self):
self.user.is_staff = True self.user.is_staff = True
@ -149,7 +158,11 @@ class FormsTestCase(TestCase):
self.assertIsInstance(user, get_user_model()) self.assertIsInstance(user, get_user_model())
self.assertFalse(user.is_superuser) self.assertFalse(user.is_superuser)
self.assertFalse(user.is_staff) 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): def test_user_settings(self):
self.c.login(**self.credentials) self.c.login(**self.credentials)

View File

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from django.conf import settings
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group from django.contrib.auth.models import Group
from django.test import TestCase from django.test import TestCase
@ -26,6 +27,6 @@ class TemplateTagsTestCase(TestCase):
) )
self.assertFalse(babybuddy.user_is_read_only(user)) 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) user.groups.add(group)
self.assertTrue(babybuddy.user_is_read_only(user)) self.assertTrue(babybuddy.user_is_read_only(user))

30
core/apps.py Normal file
View File

@ -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)