diff --git a/babybuddy/mixins.py b/babybuddy/mixins.py
new file mode 100644
index 00000000..6fadb5dd
--- /dev/null
+++ b/babybuddy/mixins.py
@@ -0,0 +1,14 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.contrib.auth.mixins import AccessMixin
+
+
+class StaffOnlyMixin(AccessMixin):
+ """
+ Verify the current user is staff.
+ """
+ def dispatch(self, request, *args, **kwargs):
+ if not request.user.is_staff:
+ return self.handle_no_permission()
+ return super().dispatch(request, *args, **kwargs)
diff --git a/babybuddy/templates/babybuddy/nav-dropdown.html b/babybuddy/templates/babybuddy/nav-dropdown.html
index f466313a..0ca8961f 100644
--- a/babybuddy/templates/babybuddy/nav-dropdown.html
+++ b/babybuddy/templates/babybuddy/nav-dropdown.html
@@ -184,10 +184,8 @@
API Browser
- {% if perms.admin.add_user %}
- Users
- {% endif %}
{% if request.user.is_staff %}
+ Users
Backend Admin
diff --git a/babybuddy/tests/tests_forms.py b/babybuddy/tests/tests_forms.py
index d7a7ebb9..a6855ef8 100644
--- a/babybuddy/tests/tests_forms.py
+++ b/babybuddy/tests/tests_forms.py
@@ -56,6 +56,8 @@ class FormsTestCase(TestCase):
self.assertEqual(page.status_code, 200)
def test_user_forms(self):
+ self.user.is_staff = True
+ self.user.save()
self.c.login(**self.credentials)
params = {
diff --git a/babybuddy/tests/tests_views.py b/babybuddy/tests/tests_views.py
index 2d1839c1..b4224d9a 100644
--- a/babybuddy/tests/tests_views.py
+++ b/babybuddy/tests/tests_views.py
@@ -62,6 +62,12 @@ class ViewsTestCase(TestCase):
self.assertEqual(page.status_code, 200)
def test_user_views(self):
+ # Staff setting is required to access user management.
+ page = self.c.get('/users/')
+ self.assertEqual(page.status_code, 302)
+ self.user.is_staff = True
+ self.user.save()
+
page = self.c.get('/users/')
self.assertEqual(page.status_code, 200)
page = self.c.get('/users/add/')
diff --git a/babybuddy/views.py b/babybuddy/views.py
index c200d721..cce016a4 100644
--- a/babybuddy/views.py
+++ b/babybuddy/views.py
@@ -17,6 +17,7 @@ from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django_filters.views import FilterView
from babybuddy import forms
+from babybuddy.mixins import StaffOnlyMixin
from core import models
@@ -40,16 +41,16 @@ class RootRouter(LoginRequiredMixin, RedirectView):
return super(RootRouter, self).get_redirect_url(self, *args, **kwargs)
-class UserList(PermissionRequiredMixin, FilterView):
+class UserList(StaffOnlyMixin, FilterView):
model = User
template_name = 'babybuddy/user_list.html'
ordering = 'username'
- permission_required = ('admin.add_user',)
paginate_by = 10
filter_fields = ('username', 'first_name', 'last_name', 'email')
-class UserAdd(PermissionRequiredMixin, SuccessMessageMixin, CreateView):
+class UserAdd(StaffOnlyMixin, PermissionRequiredMixin, SuccessMessageMixin,
+ CreateView):
model = User
template_name = 'babybuddy/user_form.html'
permission_required = ('admin.add_user',)
@@ -58,7 +59,8 @@ class UserAdd(PermissionRequiredMixin, SuccessMessageMixin, CreateView):
success_message = 'User %(username)s added!'
-class UserUpdate(PermissionRequiredMixin, SuccessMessageMixin, UpdateView):
+class UserUpdate(StaffOnlyMixin, PermissionRequiredMixin, SuccessMessageMixin,
+ UpdateView):
model = User
template_name = 'babybuddy/user_form.html'
permission_required = ('admin.change_user',)
@@ -67,7 +69,8 @@ class UserUpdate(PermissionRequiredMixin, SuccessMessageMixin, UpdateView):
success_message = 'User %(username)s updated.'
-class UserDelete(PermissionRequiredMixin, DeleteView):
+class UserDelete(StaffOnlyMixin, PermissionRequiredMixin,
+ DeleteView):
model = User
template_name = 'babybuddy/user_confirm_delete.html'
permission_required = ('admin.delete_user',)