diff --git a/benefits/core/admin/__init__.py b/benefits/core/admin/__init__.py index d8541418b..4dbbc005e 100644 --- a/benefits/core/admin/__init__.py +++ b/benefits/core/admin/__init__.py @@ -12,6 +12,7 @@ add_transit_agency_staff_user_to_group, add_google_sso_userinfo, is_staff_member, + is_staff_member_or_superuser, pre_login_user, ) @@ -27,5 +28,6 @@ "add_transit_agency_staff_user_to_group", "add_google_sso_userinfo", "is_staff_member", + "is_staff_member_or_superuser", "pre_login_user", ] diff --git a/benefits/core/admin/enrollment.py b/benefits/core/admin/enrollment.py index 0e79642dd..964cb9004 100644 --- a/benefits/core/admin/enrollment.py +++ b/benefits/core/admin/enrollment.py @@ -5,7 +5,7 @@ from adminsortable2.admin import SortableAdminMixin from benefits.core import models -from .users import is_staff_member +from .users import is_staff_member_or_superuser @admin.register(models.EnrollmentEvent) @@ -18,7 +18,7 @@ def get_readonly_fields(self, request: HttpRequest, obj=None): def has_add_permission(self, request: HttpRequest, obj=None): if settings.RUNTIME_ENVIRONMENT() == settings.RUNTIME_ENVS.PROD: return False - elif request.user and (request.user.is_superuser or is_staff_member(request.user)): + elif request.user and is_staff_member_or_superuser(request.user): return True else: return False @@ -34,13 +34,13 @@ def has_change_permission(self, request: HttpRequest, obj=None): def has_delete_permission(self, request: HttpRequest, obj=None): if settings.RUNTIME_ENVIRONMENT() == settings.RUNTIME_ENVS.PROD: return False - elif request.user and (request.user.is_superuser or is_staff_member(request.user)): + elif request.user and is_staff_member_or_superuser(request.user): return True else: return False def has_view_permission(self, request: HttpRequest, obj=None): - if request.user and (request.user.is_superuser or is_staff_member(request.user)): + if request.user and is_staff_member_or_superuser(request.user): return True else: return False diff --git a/benefits/core/admin/users.py b/benefits/core/admin/users.py index 94cea9deb..582d6faa4 100644 --- a/benefits/core/admin/users.py +++ b/benefits/core/admin/users.py @@ -50,10 +50,21 @@ def add_transit_agency_staff_user_to_group(user, request): def is_staff_member(user): + """Determine if a user is a member of the staff group of Benefits + + The staff group of Benefits is also called the 'Cal-ITP' group (defined in settings.STAFF_GROUP_NAME) + and it is not to be confused with Django's concept of 'staff' which simply means users that can log in to the admin. + """ + staff_group = Group.objects.get(name=settings.STAFF_GROUP_NAME) return staff_group.user_set.contains(user) +def is_staff_member_or_superuser(user): + """Determine if a user is a member of the staff group of Benefits or if it is a superuser.""" + return user.is_superuser or is_staff_member(user) + + def pre_login_user(user, request): logger.debug(f"Running pre-login callback for user: {user.username}") add_google_sso_userinfo(user, request) diff --git a/tests/pytest/core/admin/test_users.py b/tests/pytest/core/admin/test_users.py index 23fd4089c..09e4d7ad1 100644 --- a/tests/pytest/core/admin/test_users.py +++ b/tests/pytest/core/admin/test_users.py @@ -2,7 +2,7 @@ from django.contrib.auth.models import User, Group import benefits.core.admin -from benefits.core.admin.users import GOOGLE_USER_INFO_URL, pre_login_user +from benefits.core.admin.users import GOOGLE_USER_INFO_URL, is_staff_member, is_staff_member_or_superuser, pre_login_user @pytest.fixture @@ -21,6 +21,57 @@ def test_admin_registered(client): assert "google_sso/login.html" in response.template_name +@pytest.mark.django_db +def test_is_staff_member_regular_user(model_AdminUser, settings): + staff_group = Group.objects.get(name=settings.STAFF_GROUP_NAME) + assert not staff_group.user_set.contains(model_AdminUser) + assert not is_staff_member(model_AdminUser) + + +@pytest.mark.django_db +def test_is_staff_member_staff_user(model_AdminUser, settings): + staff_group = Group.objects.get(name=settings.STAFF_GROUP_NAME) + staff_group.user_set.add(model_AdminUser) + assert staff_group.user_set.contains(model_AdminUser) + assert is_staff_member(model_AdminUser) + + +@pytest.mark.django_db +def test_is_staff_member_superuser(model_AdminUser, settings): + model_AdminUser.is_superuser = True + model_AdminUser.save() + staff_group = Group.objects.get(name=settings.STAFF_GROUP_NAME) + assert not staff_group.user_set.contains(model_AdminUser) + assert not is_staff_member(model_AdminUser) + + +@pytest.mark.django_db +def test_is_staff_member_or_superuser_regular_user(model_AdminUser, settings): + assert not model_AdminUser.is_superuser + + staff_group = Group.objects.get(name=settings.STAFF_GROUP_NAME) + + assert not staff_group.user_set.contains(model_AdminUser) + assert not is_staff_member_or_superuser(model_AdminUser) + + +@pytest.mark.django_db +def test_is_staff_member_or_superuser_staff_member(model_AdminUser, settings): + staff_group = Group.objects.get(name=settings.STAFF_GROUP_NAME) + staff_group.user_set.add(model_AdminUser) + + assert not model_AdminUser.is_superuser + assert is_staff_member_or_superuser(model_AdminUser) + + +@pytest.mark.django_db +def test_is_staff_member_or_superuser_superuser(model_AdminUser): + model_AdminUser.is_superuser = True + model_AdminUser.save() + + assert is_staff_member_or_superuser(model_AdminUser) + + @pytest.mark.django_db def test_pre_login_user(mocker, model_AdminUser): assert model_AdminUser.email == "user@calitp.org"