From bec7105bde7de8580263e919cdc0beab150ad255 Mon Sep 17 00:00:00 2001 From: sks444 <krishnasingh.ss30@gmail.com> Date: Mon, 3 Aug 2020 17:11:50 +0530 Subject: [PATCH] Use drf ViewSet and routers instead of api view --- hypha/apply/api/v1/mixin.py | 10 +++ hypha/apply/api/v1/serializers.py | 8 +- hypha/apply/api/v1/urls.py | 42 ++++----- hypha/apply/api/v1/views.py | 139 +++++++++++++++--------------- 4 files changed, 99 insertions(+), 100 deletions(-) create mode 100644 hypha/apply/api/v1/mixin.py diff --git a/hypha/apply/api/v1/mixin.py b/hypha/apply/api/v1/mixin.py new file mode 100644 index 000000000..67d8fe843 --- /dev/null +++ b/hypha/apply/api/v1/mixin.py @@ -0,0 +1,10 @@ +from django.shortcuts import get_object_or_404 + +from hypha.apply.funds.models import ApplicationSubmission + + +class SubmissionNextedMixin: + def get_submission_object(self): + return get_object_or_404( + ApplicationSubmission, id=self.kwargs['submission_pk'] + ) diff --git a/hypha/apply/api/v1/serializers.py b/hypha/apply/api/v1/serializers.py index 8778d56b5..60a086c2d 100644 --- a/hypha/apply/api/v1/serializers.py +++ b/hypha/apply/api/v1/serializers.py @@ -110,7 +110,7 @@ class TimestampField(serializers.Field): class SubmissionListSerializer(serializers.ModelSerializer): - url = serializers.HyperlinkedIdentityField(view_name='api:v1:submissions:detail') + url = serializers.HyperlinkedIdentityField(view_name='api:v1:submissions-detail') round = serializers.SerializerMethodField() last_update = TimestampField() @@ -199,14 +199,14 @@ class RoundLabSerializer(serializers.ModelSerializer): class CommentSerializer(serializers.ModelSerializer): user = serializers.StringRelatedField() message = serializers.SerializerMethodField() - edit_url = serializers.HyperlinkedIdentityField(view_name='api:v1:comments:edit') + edit_url = serializers.HyperlinkedIdentityField(view_name='api:v1:comments-edit') editable = serializers.SerializerMethodField() timestamp = TimestampField(read_only=True) edited = TimestampField(read_only=True) class Meta: model = Activity - fields = ('id', 'timestamp', 'user', 'source', 'message', 'visibility', 'edited', 'edit_url', 'editable') + fields = ('id', 'timestamp', 'user', 'message', 'visibility', 'edited', 'edit_url', 'editable') def get_message(self, obj): return bleach_value(markdown(obj.message)) @@ -217,7 +217,7 @@ class CommentSerializer(serializers.ModelSerializer): class CommentCreateSerializer(serializers.ModelSerializer): user = serializers.StringRelatedField() - edit_url = serializers.HyperlinkedIdentityField(view_name='api:v1:comments:edit') + edit_url = serializers.HyperlinkedIdentityField(view_name='api:v1:comments-edit') editable = serializers.SerializerMethodField() timestamp = TimestampField(read_only=True) edited = TimestampField(read_only=True) diff --git a/hypha/apply/api/v1/urls.py b/hypha/apply/api/v1/urls.py index 102a35920..55fbd1ebb 100644 --- a/hypha/apply/api/v1/urls.py +++ b/hypha/apply/api/v1/urls.py @@ -1,31 +1,23 @@ -from django.urls import include, path +from rest_framework_nested import routers from .views import ( - CommentEdit, - CommentList, - CommentListCreate, - RoundLabDetail, - RoundLabList, - SubmissionAction, - SubmissionDetail, - SubmissionList, + SubmissionViewSet, + SubmissionActionViewSet, + SubmissionCommentViewSet, + CommentViewSet, + RoundViewSet, ) app_name = 'v1' -urlpatterns = [ - path('submissions/', include(([ - path('', SubmissionList.as_view(), name='list'), - path('<int:pk>/', SubmissionDetail.as_view(), name='detail'), - path('<int:pk>/actions/', SubmissionAction.as_view(), name='actions'), - path('<int:pk>/comments/', CommentListCreate.as_view(), name='comments'), - ], 'submissions'))), - path('rounds/', include(([ - path('', RoundLabList.as_view(), name='list'), - path('<int:pk>/', RoundLabDetail.as_view(), name='detail'), - ], 'rounds'))), - path('comments/', include(([ - path('', CommentList.as_view(), name='list'), - path('<int:pk>/edit/', CommentEdit.as_view(), name='edit'), - ], 'comments'))) -] + +router = routers.SimpleRouter() +router.register(r'submissions', SubmissionViewSet, base_name='submissions') +router.register(r'comments', CommentViewSet, base_name='comments') +router.register(r'rounds', RoundViewSet, base_name='rounds') + +submission_router = routers.NestedSimpleRouter(router, r'submissions', lookup='submission') +submission_router.register(r'actions', SubmissionActionViewSet, base_name='submission-actions') +submission_router.register(r'comments', SubmissionCommentViewSet, base_name='submission-comments') + +urlpatterns = router.urls + submission_router.urls diff --git a/hypha/apply/api/v1/views.py b/hypha/apply/api/v1/views.py index 3d483dfd5..93e27dcc7 100644 --- a/hypha/apply/api/v1/views.py +++ b/hypha/apply/api/v1/views.py @@ -3,9 +3,10 @@ from django.db import transaction from django.db.models import Prefetch, Q from django.utils import timezone from django_filters import rest_framework as filters -from rest_framework import generics, mixins, permissions +from rest_framework import mixins, permissions, viewsets from rest_framework.exceptions import NotFound, PermissionDenied, ValidationError from rest_framework.response import Response +from rest_framework.decorators import action from rest_framework_api_key.permissions import HasAPIKey from wagtail.core.models import Page @@ -33,6 +34,7 @@ from .serializers import ( SubmissionDetailSerializer, SubmissionListSerializer, ) +from .mixin import SubmissionNextedMixin class RoundLabFilter(filters.ModelChoiceFilter): @@ -67,12 +69,7 @@ class SubmissionsFilter(filters.FilterSet): return qs.inactive() -class SubmissionList(generics.ListAPIView): - """ - List all the submissions. - """ - queryset = ApplicationSubmission.objects.current().with_latest_update() - serializer_class = SubmissionListSerializer +class SubmissionViewSet(viewsets.ReadOnlyModelViewSet): permission_classes = ( HasAPIKey | permissions.IsAuthenticated, HasAPIKey | IsApplyStaffUser, ) @@ -80,33 +77,42 @@ class SubmissionList(generics.ListAPIView): filter_class = SubmissionsFilter pagination_class = StandardResultsSetPagination + def get_serializer_class(self): + if self.action == 'list': + return SubmissionListSerializer + return SubmissionDetailSerializer -class SubmissionDetail(generics.RetrieveAPIView): - """ - Get details about a submission by it's id. - """ - queryset = ApplicationSubmission.objects.all().prefetch_related( - Prefetch('reviews', Review.objects.submitted()), - ) - serializer_class = SubmissionDetailSerializer - permission_classes = ( - permissions.IsAuthenticated, IsApplyStaffUser, - ) - + def get_queryset(self): + if self.action == 'list': + return ApplicationSubmission.objects.current().with_latest_update() + return ApplicationSubmission.objects.all().prefetch_related( + Prefetch('reviews', Review.objects.submitted()), + ) -class SubmissionAction(generics.RetrieveAPIView): - """ - List all the actions that can be taken on a submission. - E.g. All the states this submission can be transistion to. - """ - queryset = ApplicationSubmission.objects.all() +class SubmissionActionViewSet( + SubmissionNextedMixin, + viewsets.GenericViewSet +): serializer_class = SubmissionActionSerializer permission_classes = ( permissions.IsAuthenticated, IsApplyStaffUser, ) - def post(self, request, *args, **kwargs): + def get_object(self): + return self.get_submission_object() + + def list(self, request, *args, **kwargs): + """ + List all the actions that can be taken on a submission. + + E.g. All the states this submission can be transistion to. + """ + obj = self.get_object() + ser = self.get_serializer(obj) + return Response(ser.data) + + def create(self, request, *args, **kwargs): """ Transistion a submission from one state to other. @@ -146,24 +152,11 @@ class SubmissionAction(generics.RetrieveAPIView): }) -class RoundLabDetail(generics.RetrieveAPIView): - """ - Get detail about a round or a lab. - """ - queryset = RoundsAndLabs.objects.all() - serializer_class = RoundLabDetailSerializer - permission_classes = ( - permissions.IsAuthenticated, IsApplyStaffUser, - ) - - def get_object(self): - return super().get_object().specific - - -class RoundLabList(generics.ListAPIView): - """ - List all the rounds and labs current user has access to. - """ +class RoundViewSet( + mixins.RetrieveModelMixin, + mixins.ListModelMixin, + viewsets.GenericViewSet +): queryset = RoundsAndLabs.objects.specific() serializer_class = RoundLabSerializer permission_classes = ( @@ -171,6 +164,11 @@ class RoundLabList(generics.ListAPIView): ) pagination_class = StandardResultsSetPagination + def get_serializer_class(self): + if self.action == 'list': + return RoundLabSerializer + return RoundLabDetailSerializer + class NewerThanFilter(filters.ModelChoiceFilter): def filter(self, qs, value): @@ -195,24 +193,12 @@ class AllCommentFilter(CommentFilter): fields = CommentFilter.Meta.fields + ['source_object_id'] -class CommentList(generics.ListAPIView): - """ - List all the comments for a user. - """ - queryset = Activity.comments.all() - serializer_class = CommentSerializer - permission_classes = ( - permissions.IsAuthenticated, IsApplyStaffUser, - ) - filter_backends = (filters.DjangoFilterBackend,) - filter_class = AllCommentFilter - pagination_class = StandardResultsSetPagination - - def get_queryset(self): - return super().get_queryset().visible_to(self.request.user) - - -class CommentListCreate(generics.ListCreateAPIView): +class SubmissionCommentViewSet( + SubmissionNextedMixin, + mixins.ListModelMixin, + mixins.CreateModelMixin, + viewsets.GenericViewSet +): """ List all the comments on a submission. """ @@ -227,7 +213,7 @@ class CommentListCreate(generics.ListCreateAPIView): def get_queryset(self): return super().get_queryset().filter( - submission=self.kwargs['pk'] + submission=self.get_submission_object() ).visible_to(self.request.user) def perform_create(self, serializer): @@ -238,7 +224,7 @@ class CommentListCreate(generics.ListCreateAPIView): timestamp=timezone.now(), type=COMMENT, user=self.request.user, - source=ApplicationSubmission.objects.get(pk=self.kwargs['pk']) + source=self.get_submission_object() ) messenger( MESSAGES.COMMENT, @@ -249,10 +235,9 @@ class CommentListCreate(generics.ListCreateAPIView): ) -class CommentEdit( - mixins.RetrieveModelMixin, - mixins.CreateModelMixin, - generics.GenericAPIView, +class CommentViewSet( + mixins.ListModelMixin, + viewsets.GenericViewSet, ): """ Edit a comment. @@ -263,11 +248,20 @@ class CommentEdit( permissions.IsAuthenticated, IsAuthor ) - def post(self, request, *args, **kwargs): - return self.edit(request, *args, **kwargs) + def get_serializer_class(self): + if self.action == 'list': + return CommentSerializer + return CommentEditSerializer - @transaction.atomic + def get_queryset(self): + return super().get_queryset().visible_to(self.request.user) + + @action(detail=True, methods=['post']) def edit(self, request, *args, **kwargs): + return self.edit_comment(request, *args, **kwargs) + + @transaction.atomic + def edit_comment(self, request, *args, **kwargs): comment_to_edit = self.get_object() comment_to_update = self.get_object() @@ -285,3 +279,6 @@ class CommentEdit( return Response(serializer.data) return Response(self.get_serializer(comment_to_update).data) + + def perform_create(self, serializer): + serializer.save() -- GitLab