Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion mcserver/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2001,7 +2001,19 @@ def get_queryset(self):
return Subject.objects.filter(user=user).prefetch_related('subjecttags_set')

def list(self, request):
"""
Default to the user's own subjects.

admin/backend can pass ?all_subjects=true to list across all users;
no-op for other users.
"""
queryset = self.get_queryset()
all_subjects = request.query_params.get('all_subjects', 'false') == 'true'
if not all_subjects:
queryset = queryset.filter(user=request.user)
# snapshot before search/trashed/paging narrow queryset below (see total)
base_queryset = queryset

# Get quantity from post request. If it does exist, use it. If not, set -1 as default (e.g., return all)
# print(request.query_params)
is_simple = request.query_params.get('simple', 'false') == 'true'
Expand Down Expand Up @@ -2036,7 +2048,7 @@ def list(self, request):
queryset = queryset[:quantity]

serializer = (SimpleSubjectSerializer if is_simple else SubjectSerializer)(queryset, many=True)
return Response({'subjects': serializer.data, 'total': self.get_queryset().count()})
return Response({'subjects': serializer.data, 'total': base_queryset.count()})

def get_serializer_class(self):
if self.action in ['create', 'update', 'partial_update']:
Expand Down
49 changes: 43 additions & 6 deletions tests/test_permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -916,21 +916,58 @@ def _setup_subject(self):
self.subject = Subject.objects.create(name='test_subject', user=self.owner)
self.detail_url = f'/subjects/{self.subject.pk}/'

def _returned_ids(self, resp):
# Ids come back as UUIDs; compare as strings to avoid type mismatches.
return {str(s['id']) for s in resp.data['subjects']}

def test_get_list(self):
# Test GET /subjects/ (list)
# Test GET /subjects/ (list) - by default every user, including admin
# and backend, only sees their own subjects.
self._setup_subject()
other_subject = Subject.objects.create(name='other_subject', user=self.other_user)

# Exact subjects each role should see by default (their own only).
expected_ids = {
'owner': {str(self.subject.pk)},
'admin': set(),
'backend': set(),
'other': {str(other_subject.pk)},
}
for role in self.users:
with self.subTest(role=role):
self.client.force_authenticate(user=self.users[role])
resp = self.client.get(self.list_url)

if role in ['owner', 'admin', 'backend', 'other']:
if role in expected_ids:
self.assertEqual(resp.status_code, 200)
self.assertEqual(self._returned_ids(resp), expected_ids[role])
self.assertEqual(resp.data['total'], len(expected_ids[role]))
else:
self.assertEqual(resp.status_code, 403)

if role in ['owner', 'admin', 'backend']:
self.assertEqual(len(resp.data['subjects']), 1)
else:
self.assertEqual(len(resp.data['subjects']), 0)
def test_get_list_all_subjects_flag(self):
# Test GET /subjects/?all_subjects=true - admin/backend can list every
# user's subjects; the flag is ignored for everyone else.
self._setup_subject()
other_subject = Subject.objects.create(name='other_subject', user=self.other_user)
all_ids = {str(self.subject.pk), str(other_subject.pk)}

# Elevated roles see every subject; everyone else still only their own.
expected_ids = {
'admin': all_ids,
'backend': all_ids,
'owner': {str(self.subject.pk)},
'other': {str(other_subject.pk)},
}
for role in self.users:
with self.subTest(role=role):
self.client.force_authenticate(user=self.users[role])
resp = self.client.get(self.list_url, {'all_subjects': 'true'})

if role in expected_ids:
self.assertEqual(resp.status_code, 200)
self.assertEqual(self._returned_ids(resp), expected_ids[role])
self.assertEqual(resp.data['total'], len(expected_ids[role]))
else:
self.assertEqual(resp.status_code, 403)

Expand Down