Skip to content

Commit f5d144b

Browse files
committed
Convert session views to nested viewsets
This includes modifying how `WorkspaceChildMixin` (our custom extension of `NestedViewSetMixin`) works: now the mixin is a mixin generator function that takes an optional prefix value meant to allow for it to reach through the `Session` model's related resource (either a `Table` or `Network`) to figure out what workspace it belongs to.
1 parent ba5f4e6 commit f5d144b

File tree

7 files changed

+80
-46
lines changed

7 files changed

+80
-46
lines changed

multinet/api/views/common.py

Lines changed: 58 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -41,40 +41,64 @@ def paginate_queryset(self, query: ArangoQuery, request: Request) -> List[Dict]:
4141
return list(cur)
4242

4343

44-
class WorkspaceChildMixin(NestedViewSetMixin):
45-
def get_queryset(self):
46-
"""
47-
Get the queryset for workspace child enpoints.
48-
49-
Check that the requeting user has appropriate permissions for the associated workspace.
50-
"""
51-
child_objects = super().get_queryset()
52-
53-
# prevent warning for schema generation incompatibility
54-
if getattr(self, 'swagger_fake_view', False):
55-
return child_objects.none()
56-
57-
parent_query_dict = self.get_parents_query_dict()
58-
workspace = get_object_or_404(
59-
Workspace.objects.select_related('owner'), name=parent_query_dict['workspace__name']
60-
)
61-
62-
# No user or user permission required for public workspaces
63-
if workspace.public:
64-
return child_objects
65-
66-
# Private workspace
67-
request_user = self.request.user
68-
if not request_user.is_authenticated: # anonymous user
69-
raise Http404
44+
def WorkspaceChildMixin(prefix=None):
45+
class _WorkspaceChildMixin(NestedViewSetMixin):
46+
def my_lookup_field(self):
47+
field = 'workspace__name'
48+
if prefix is not None:
49+
field = f'{prefix}__{field}'
50+
51+
return field
52+
53+
def get_parents_query_dict(self):
54+
parents_query_dict = super().get_parents_query_dict()
55+
56+
print(parents_query_dict)
57+
58+
# Replace the standard lookup field with one that (possibly) goes
59+
# through the session object's related network or table object.
60+
new_field = self.my_lookup_field()
61+
if not new_field in parents_query_dict:
62+
old_field = 'workspace__name'
63+
parents_query_dict[new_field] = parents_query_dict.pop(old_field)
64+
65+
return parents_query_dict
66+
67+
def get_queryset(self):
68+
"""
69+
Get the queryset for workspace child enpoints.
7070
71-
workspace_role = WorkspaceRole.objects.filter(
72-
workspace=workspace, user=request_user
73-
).first()
71+
Check that the requeting user has appropriate permissions for the associated workspace.
72+
"""
73+
child_objects = super().get_queryset()
7474

75-
# If the user is at least a reader or the owner, grant access
76-
if workspace_role is not None or workspace.owner == request_user:
77-
return child_objects
75+
# prevent warning for schema generation incompatibility
76+
if getattr(self, 'swagger_fake_view', False):
77+
return child_objects.none()
78+
79+
parent_query_dict = self.get_parents_query_dict()
80+
workspace = get_object_or_404(
81+
Workspace.objects.select_related('owner'), name=parent_query_dict[self.my_lookup_field()]
82+
)
83+
84+
# No user or user permission required for public workspaces
85+
if workspace.public:
86+
return child_objects
87+
88+
# Private workspace
89+
request_user = self.request.user
90+
if not request_user.is_authenticated: # anonymous user
91+
raise Http404
92+
93+
workspace_role = WorkspaceRole.objects.filter(
94+
workspace=workspace, user=request_user
95+
).first()
96+
97+
# If the user is at least a reader or the owner, grant access
98+
if workspace_role is not None or workspace.owner == request_user:
99+
return child_objects
100+
101+
# Read access denied
102+
raise Http404
78103

79-
# Read access denied
80-
raise Http404
104+
return _WorkspaceChildMixin

multinet/api/views/network.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ def validate_edge_table(
7070
return Response(serialized_resp.data, status=status.HTTP_400_BAD_REQUEST)
7171

7272

73-
class NetworkViewSet(WorkspaceChildMixin, DetailSerializerMixin, ReadOnlyModelViewSet):
73+
class NetworkViewSet(WorkspaceChildMixin(), DetailSerializerMixin, ReadOnlyModelViewSet):
7474
queryset = Network.objects.all().select_related('workspace')
7575
lookup_field = 'name'
7676

multinet/api/views/query.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from .serializers import AqlQueryResultsSerializer, AqlQuerySerializer, AqlQueryTaskSerializer
1515

1616

17-
class AqlQueryViewSet(WorkspaceChildMixin, ReadOnlyModelViewSet):
17+
class AqlQueryViewSet(WorkspaceChildMixin(), ReadOnlyModelViewSet):
1818
queryset = AqlQuery.objects.all().select_related('workspace')
1919
permission_classes = [IsAuthenticatedOrReadOnly]
2020
serializer_class = AqlQueryTaskSerializer

multinet/api/views/session.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from django.http.response import Http404
12
from drf_yasg.utils import swagger_auto_schema
23
from rest_framework import serializers, status
34
from rest_framework.decorators import action
@@ -12,6 +13,7 @@
1213

1314
from ..models import NetworkSession, TableSession
1415
from .serializers import NetworkSessionSerializer, TableSessionSerializer
16+
from .common import WorkspaceChildMixin
1517

1618

1719
class SessionCreateSerializer(serializers.Serializer):
@@ -51,11 +53,11 @@ def state(self, request, pk=None):
5153
return Response(status=status.HTTP_204_NO_CONTENT)
5254

5355

54-
class NetworkSessionViewSet(SessionViewSet):
55-
queryset = NetworkSession.objects.all()
56+
class NetworkSessionViewSet(WorkspaceChildMixin('network'), SessionViewSet):
57+
queryset = NetworkSession.objects.all().select_related('network__workspace')
5658
serializer_class = NetworkSessionSerializer
5759

5860

59-
class TableSessionViewSet(SessionViewSet):
60-
queryset = TableSession.objects.all()
61+
class TableSessionViewSet(WorkspaceChildMixin('table'), SessionViewSet):
62+
queryset = TableSession.objects.all().select_related('table__workspace')
6163
serializer_class = TableSessionSerializer

multinet/api/views/table.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class RowDeleteResponseSerializer(serializers.Serializer):
3636
errors = serializers.ListField(child=serializers.JSONField())
3737

3838

39-
class TableViewSet(WorkspaceChildMixin, ReadOnlyModelViewSet):
39+
class TableViewSet(WorkspaceChildMixin(), ReadOnlyModelViewSet):
4040
queryset = Table.objects.all().select_related('workspace')
4141
lookup_field = 'name'
4242

multinet/api/views/upload.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ def field_value_object_key(serializer: serializers.Serializer) -> Optional[str]:
3838
return object_key
3939

4040

41-
class UploadViewSet(WorkspaceChildMixin, ReadOnlyModelViewSet):
41+
class UploadViewSet(WorkspaceChildMixin(), ReadOnlyModelViewSet):
4242
queryset = Upload.objects.all().select_related('workspace')
4343

4444
permission_classes = [IsAuthenticatedOrReadOnly]

multinet/urls.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,18 @@
4444
basename='query',
4545
parents_query_lookups=[f'workspace__{WorkspaceViewSet.lookup_field}'],
4646
)
47-
48-
router.register('sessions/network', NetworkSessionViewSet)
49-
router.register('sessions/table', TableSessionViewSet)
50-
47+
workspaces_routes.register(
48+
'sessions/network',
49+
NetworkSessionViewSet,
50+
basename='session',
51+
parents_query_lookups=[f'workspace__{WorkspaceViewSet.lookup_field}'],
52+
)
53+
workspaces_routes.register(
54+
'sessions/table',
55+
TableSessionViewSet,
56+
basename='session',
57+
parents_query_lookups=[f'workspace__{WorkspaceViewSet.lookup_field}'],
58+
)
5159

5260
# OpenAPI generation
5361
schema_view = get_schema_view(

0 commit comments

Comments
 (0)