Skip to content

Commit 4a935ce

Browse files
authored
Merge pull request #2752 from dandi/dashboard-required-perm
Update dashboard permissions
2 parents 6ad4333 + 3e004d2 commit 4a935ce

File tree

2 files changed

+93
-3
lines changed

2 files changed

+93
-3
lines changed
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
from __future__ import annotations
2+
3+
import pytest
4+
5+
from dandiapi.api.tests.factories import UserFactory
6+
7+
8+
@pytest.mark.parametrize(
9+
('is_staff', 'is_superuser'),
10+
[
11+
(False, False),
12+
(False, True),
13+
(True, False),
14+
(True, True),
15+
],
16+
)
17+
@pytest.mark.django_db
18+
def test_dashboard_access(api_client, is_staff, is_superuser):
19+
user = UserFactory.create(is_staff=is_staff, is_superuser=is_superuser)
20+
api_client.force_login(user)
21+
resp = api_client.get('/dashboard/')
22+
23+
should_pass = is_staff or is_superuser
24+
assert resp.status_code == (200 if should_pass else 403)
25+
26+
27+
@pytest.mark.django_db
28+
def test_dashboard_access_unauthenticated(api_client):
29+
resp = api_client.get('/dashboard/')
30+
assert resp.status_code == 302
31+
32+
33+
@pytest.mark.parametrize(
34+
('is_staff', 'is_superuser'),
35+
[
36+
(False, False),
37+
(False, True),
38+
(True, False),
39+
(True, True),
40+
],
41+
)
42+
@pytest.mark.django_db
43+
def test_user_approval_access(api_client, is_staff, is_superuser):
44+
user = UserFactory.create(is_staff=is_staff, is_superuser=is_superuser)
45+
api_client.force_login(user)
46+
47+
other_user = UserFactory.create()
48+
resp = api_client.get(f'/dashboard/user/{other_user.username}/')
49+
50+
should_pass = is_staff or is_superuser
51+
assert resp.status_code == (200 if should_pass else 403)
52+
53+
54+
@pytest.mark.django_db
55+
def test_user_approval_access_unauthenticated(api_client):
56+
other_user = UserFactory.create()
57+
resp = api_client.get(f'/dashboard/user/{other_user.username}/')
58+
assert resp.status_code == 302
59+
60+
61+
@pytest.mark.parametrize(
62+
('is_staff', 'is_superuser'),
63+
[
64+
(False, False),
65+
(False, True),
66+
(True, False),
67+
(True, True),
68+
],
69+
)
70+
@pytest.mark.django_db
71+
def test_mailchimp_view_access(api_client, is_staff, is_superuser):
72+
user = UserFactory.create(is_staff=is_staff, is_superuser=is_superuser)
73+
api_client.force_login(user)
74+
75+
resp = api_client.get('/dashboard/mailchimp/')
76+
77+
should_pass = is_staff or is_superuser
78+
assert resp.status_code == (200 if should_pass else 403)
79+
80+
81+
@pytest.mark.django_db
82+
def test_mailchimp_view_access_unauthenticated(api_client):
83+
resp = api_client.get('/dashboard/mailchimp/')
84+
assert resp.status_code == 403

dandiapi/api/views/dashboard.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from __future__ import annotations
22

33
import csv
4+
import typing
45
from typing import TYPE_CHECKING
56

67
from django.conf import settings
@@ -25,7 +26,8 @@
2526

2627
class DashboardMixin(LoginRequiredMixin, UserPassesTestMixin):
2728
def test_func(self):
28-
return self.request.user.is_superuser
29+
user = typing.cast('User', self.request.user)
30+
return user.is_staff or user.is_superuser
2931

3032

3133
class DashboardView(DashboardMixin, TemplateView):
@@ -87,6 +89,10 @@ def _users(self):
8789

8890
def mailchimp_csv_view(request: HttpRequest) -> StreamingHttpResponse:
8991
"""Generate a Mailchimp-compatible CSV file of all active users."""
92+
# If they are authenticated but are not a superuser or staff, deny access
93+
if not (request.user.is_superuser or request.user.is_staff):
94+
raise PermissionDenied
95+
9096
# Exclude the django-guardian anonymous user account.
9197
users = User.objects.filter(metadata__status=UserMetadata.Status.APPROVED).exclude(
9298
username='AnonymousUser'
@@ -125,8 +131,8 @@ def user_approval_view(request: HttpRequest, username: str):
125131
if not request.user.is_authenticated:
126132
return HttpResponseRedirect(redirect_to=f'{settings.LOGIN_URL}?next={request.path}')
127133

128-
# If they are authenticated but are not a superuser, deny access
129-
if not request.user.is_superuser:
134+
# If they are authenticated but are not a superuser or staff, deny access
135+
if not (request.user.is_superuser or request.user.is_staff):
130136
raise PermissionDenied
131137

132138
user: User = get_object_or_404(User.objects.select_related('metadata'), username=username)

0 commit comments

Comments
 (0)