Skip to content

Commit c261684

Browse files
committed
Split up v2 serializers into admin and non-admin versions
This uses a mixin class to the viewset to select the serializer class based on whether the user is staff or not.
1 parent 95433fa commit c261684

File tree

2 files changed

+50
-53
lines changed

2 files changed

+50
-53
lines changed

readthedocs/restapi/serializers.py

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,9 @@ class Meta(object):
2626
)
2727

2828

29-
class ProjectSerializerFull(ProjectSerializer):
29+
class ProjectAdminSerializer(ProjectSerializer):
3030

31-
"""Serializer to return all Project fields, for use by builder instances"""
32-
33-
class Meta(object):
34-
model = Project
35-
# The following fields are required by builder processes
31+
class Meta(ProjectSerializer.Meta):
3632
fields = ProjectSerializer.Meta.fields + (
3733
'enable_epub_build',
3834
'enable_pdf_build',
@@ -66,7 +62,15 @@ class Meta(object):
6662
)
6763

6864

65+
class VersionAdminSerializer(VersionSerializer):
66+
67+
"""Version serializer that returns admin project data"""
68+
69+
project = ProjectAdminSerializer()
70+
71+
6972
class BuildCommandSerializer(serializers.ModelSerializer):
73+
7074
run_time = serializers.ReadOnlyField()
7175

7276
class Meta(object):
@@ -76,7 +80,7 @@ class Meta(object):
7680

7781
class BuildSerializer(serializers.ModelSerializer):
7882

79-
"""Readonly version of the build serializer, used for user facing display"""
83+
"""Build serializer for user display, doesn't display internal fields"""
8084

8185
commands = BuildCommandSerializer(many=True, read_only=True)
8286
state_display = serializers.ReadOnlyField(source='get_state_display')
@@ -86,13 +90,12 @@ class Meta(object):
8690
exclude = ('builder',)
8791

8892

89-
class BuildSerializerFull(BuildSerializer):
93+
class BuildAdminSerializer(BuildSerializer):
9094

91-
"""Writeable Build instance serializer, for admin access by builders"""
95+
"""Build serializer for display to admin users and build instances"""
9296

93-
class Meta(object):
94-
model = Build
95-
exclude = ('')
97+
class Meta(BuildSerializer.Meta):
98+
exclude = ()
9699

97100

98101
class SearchIndexSerializer(serializers.Serializer):

readthedocs/restapi/views/model_views.py

Lines changed: 35 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -21,36 +21,52 @@
2121

2222
from ..permissions import (APIPermission, APIRestrictedPermission,
2323
RelatedProjectIsOwner, IsOwner)
24-
from ..serializers import (BuildSerializerFull, BuildSerializer,
25-
BuildCommandSerializer, ProjectSerializer,
26-
ProjectSerializerFull, VersionSerializer,
24+
from ..serializers import (BuildSerializer, BuildAdminSerializer,
25+
BuildCommandSerializer,
26+
ProjectSerializer, ProjectAdminSerializer,
27+
VersionSerializer, VersionAdminSerializer,
2728
DomainSerializer, RemoteOrganizationSerializer,
2829
RemoteRepositorySerializer)
2930
from .. import utils as api_utils
3031

3132
log = logging.getLogger(__name__)
3233

3334

34-
class ProjectViewSet(viewsets.ModelViewSet):
35+
class UserSelectViewSet(viewsets.ModelViewSet):
36+
37+
"""View set that varies serializer class based on request user credentials
38+
39+
Viewsets using this class should have an attribute `admin_serializer_class`,
40+
which is a serializer that might have more fields that only admin/staff
41+
users require. If the user is staff, this class will be returned instead.
42+
"""
43+
44+
def get_serializer_class(self):
45+
try:
46+
if self.request.user.is_staff and self.admin_serializer_class is not None:
47+
return self.admin_serializer_class
48+
except AttributeError:
49+
pass
50+
return self.serializer_class
51+
52+
def get_queryset(self):
53+
"""Use our API manager method to determine authorization on queryset"""
54+
return self.model.objects.api(self.request.user)
55+
56+
57+
class ProjectViewSet(UserSelectViewSet):
3558

3659
"""List, filter, etc. Projects."""
3760

3861
permission_classes = [APIPermission]
3962
renderer_classes = (JSONRenderer,)
4063
serializer_class = ProjectSerializer
64+
admin_serializer_class = ProjectAdminSerializer
4165
model = Project
4266
paginate_by = 100
4367
paginate_by_param = 'page_size'
4468
max_paginate_by = 1000
4569

46-
def get_queryset(self):
47-
return self.model.objects.api(self.request.user)
48-
49-
def get_serializer_class(self):
50-
if self.request.user.is_staff:
51-
return ProjectSerializerFull
52-
return self.serializer_class
53-
5470
@decorators.detail_route()
5571
def valid_versions(self, request, **kwargs):
5672
"""Maintain state of versions that are wanted."""
@@ -171,35 +187,22 @@ def sync_versions(self, request, **kwargs):
171187
})
172188

173189

174-
class VersionViewSet(viewsets.ModelViewSet):
190+
class VersionViewSet(UserSelectViewSet):
175191

176192
permission_classes = [APIRestrictedPermission]
177193
renderer_classes = (JSONRenderer,)
178194
serializer_class = VersionSerializer
195+
admin_serializer_class = VersionAdminSerializer
179196
model = Version
180197

181-
def get_queryset(self):
182-
return self.model.objects.api(self.request.user)
183-
184198

185-
class BuildViewSetBase(viewsets.ModelViewSet):
199+
class BuildViewSetBase(UserSelectViewSet):
186200
permission_classes = [APIRestrictedPermission]
187201
renderer_classes = (JSONRenderer,)
202+
serializer_class = BuildSerializer
203+
admin_serializer_class = BuildAdminSerializer
188204
model = Build
189205

190-
def get_queryset(self):
191-
return self.model.objects.api(self.request.user)
192-
193-
def get_serializer_class(self):
194-
"""Vary serializer class based on user status
195-
196-
This is used to allow write to write-only fields on Build by admin users
197-
and to not return those fields to non-admin users.
198-
"""
199-
if self.request.user.is_staff:
200-
return BuildSerializerFull
201-
return BuildSerializer
202-
203206

204207
class BuildViewSet(SettingsOverrideObject):
205208

@@ -208,18 +211,12 @@ class BuildViewSet(SettingsOverrideObject):
208211
_default_class = BuildViewSetBase
209212

210213

211-
class BuildCommandViewSet(viewsets.ModelViewSet):
212-
213-
"""This is currently a write-only way to update the commands on build."""
214-
214+
class BuildCommandViewSet(UserSelectViewSet):
215215
permission_classes = [APIRestrictedPermission]
216216
renderer_classes = (JSONRenderer,)
217217
serializer_class = BuildCommandSerializer
218218
model = BuildCommandResult
219219

220-
def get_queryset(self):
221-
return self.model.objects.api(self.request.user)
222-
223220

224221
class NotificationViewSet(viewsets.ReadOnlyModelViewSet):
225222
permission_classes = (permissions.IsAuthenticated, RelatedProjectIsOwner)
@@ -230,15 +227,12 @@ def get_queryset(self):
230227
return self.model.objects.api(self.request.user)
231228

232229

233-
class DomainViewSet(viewsets.ModelViewSet):
230+
class DomainViewSet(UserSelectViewSet):
234231
permission_classes = [APIRestrictedPermission]
235232
renderer_classes = (JSONRenderer,)
236233
serializer_class = DomainSerializer
237234
model = Domain
238235

239-
def get_queryset(self):
240-
return self.model.objects.api(self.request.user)
241-
242236

243237
class RemoteOrganizationViewSet(viewsets.ReadOnlyModelViewSet):
244238
permission_classes = [IsOwner]

0 commit comments

Comments
 (0)