From 55b4b8e14f3ba5b80bee032b4fa46b7b080ce64d Mon Sep 17 00:00:00 2001 From: WestOnyinsi <40661440+WestOnyinsi@users.noreply.github.com> Date: Fri, 20 Sep 2024 19:43:12 +0300 Subject: [PATCH 1/5] Update views.py- Added missing GET request parametrs to swagger --- core/orgs/views.py | 138 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 119 insertions(+), 19 deletions(-) diff --git a/core/orgs/views.py b/core/orgs/views.py index bd9ee371..37ee988e 100644 --- a/core/orgs/views.py +++ b/core/orgs/views.py @@ -1,5 +1,6 @@ from django.db.models import Count from django.http import Http404 +from drf_yasg import openapi from drf_yasg.utils import swagger_auto_schema from pydash import get from rest_framework import mixins, status, generics @@ -30,10 +31,8 @@ TRUTHY = get_truthy_values() - -class OrganizationListView(BaseAPIView, - ListWithHeadersMixin, - mixins.CreateModelMixin): +class OrganizationListView(BaseAPIView, ListWithHeadersMixin, mixins.CreateModelMixin): + model = Organization queryset = Organization.objects.filter(is_active=True) es_fields = Organization.es_fields @@ -76,7 +75,15 @@ def get_serializer_class(self): return OrganizationListSerializer - @swagger_auto_schema(manual_parameters=[org_no_members_param]) + @swagger_auto_schema( + manual_parameters=[ + openapi.Parameter('user', openapi.IN_PATH, description="Filter by username", type=openapi.TYPE_STRING), + openapi.Parameter(NO_MEMBERS, openapi.IN_QUERY, description="Filter organizations with no members", type=openapi.TYPE_BOOLEAN), + openapi.Parameter('updated_since', openapi.IN_QUERY, description="Filter by update date", type=openapi.TYPE_STRING, format=openapi.FORMAT_DATETIME), + openapi.Parameter(UPDATED_BY_USERNAME_PARAM, openapi.IN_QUERY, description="Filter by username of user who updated", type=openapi.TYPE_STRING), + ], + responses={status.HTTP_200_OK: OrganizationListSerializer(many=True)} + ) def get(self, request, *args, **kwargs): return self.list(request, *args, **kwargs) @@ -106,7 +113,6 @@ class OrganizationBaseView(BaseAPIView, RetrieveAPIView, DestroyAPIView): model = Organization queryset = Organization.objects.filter(is_active=True) - class OrganizationLogoView(OrganizationBaseView, BaseLogoView): serializer_class = OrganizationDetailSerializer @@ -115,7 +121,15 @@ def get_permissions(self): return [HasPrivateAccess(), ] return [CanViewConceptDictionary(), ] - + + @swagger_auto_schema( + manual_parameters=[ + openapi.Parameter('org', openapi.IN_PATH, description="Organization mnemonic", type=openapi.TYPE_STRING, required=True), + ], + responses={status.HTTP_200_OK: "Logo image"} + ) + def get(self, request, *args, **kwargs): + return super().get(request, *args, **kwargs) class OrganizationOverviewView(OrganizationBaseView, RetrieveAPIView, UpdateAPIView): serializer_class = OrganizationOverviewSerializer @@ -128,7 +142,15 @@ def get_permissions(self): def get_queryset(self): return super().get_queryset().filter(mnemonic=self.kwargs['org']) - + + @swagger_auto_schema( + manual_parameters=[ + openapi.Parameter('org', openapi.IN_PATH, description="Organization mnemonic", type=openapi.TYPE_STRING, required=True), + ], + responses={status.HTTP_200_OK: OrganizationOverviewSerializer()} + ) + def get(self, request, *args, **kwargs): + return super().get(request, *args, **kwargs) class OrganizationDetailView(OrganizationBaseView, mixins.UpdateModelMixin, mixins.CreateModelMixin, TaskMixin): def get_permissions(self): @@ -170,7 +192,15 @@ def destroy(self, request, *args, **kwargs): return result return Response(status=status.HTTP_204_NO_CONTENT) - + + @swagger_auto_schema( + manual_parameters=[ + openapi.Parameter('org', openapi.IN_PATH, description="Organization mnemonic", type=openapi.TYPE_STRING, required=True), + ], + responses={status.HTTP_200_OK: OrganizationDetailSerializer()} + ) + def get(self, request, *args, **kwargs): + return super().get(request, *args, **kwargs) class OrganizationClientConfigsView(ResourceClientConfigsView): lookup_field = 'org' @@ -178,6 +208,14 @@ class OrganizationClientConfigsView(ResourceClientConfigsView): queryset = Organization.objects.filter(is_active=True) permission_classes = (CanViewConceptDictionary, ) + @swagger_auto_schema( + manual_parameters=[ + openapi.Parameter('org', openapi.IN_PATH, description="Organization mnemonic", type=openapi.TYPE_STRING, required=True), + ], + responses={status.HTTP_200_OK: "Client configs"} + ) + def get(self, request, *args, **kwargs): + return super().get(request, *args, **kwargs) class OrganizationMemberView(generics.GenericAPIView): userprofile = None @@ -235,8 +273,22 @@ def delete(self, request, **kwargs): # pylint: disable=unused-argument self.userprofile.save() return Response(status=status.HTTP_204_NO_CONTENT) - - + + + @swagger_auto_schema( + manual_parameters=[ + openapi.Parameter('org', openapi.IN_PATH, description="Organization mnemonic", type=openapi.TYPE_STRING, required=True), + openapi.Parameter('user', openapi.IN_PATH, description="Username", type=openapi.TYPE_STRING, required=True), + ], + responses={ + status.HTTP_204_NO_CONTENT: "User is a member", + status.HTTP_404_NOT_FOUND: "User is not a member", + status.HTTP_403_FORBIDDEN: "Permission denied" + } + ) + def get(self, request, *args, **kwargs): + return super().get(request, *args, **kwargs) + class OrganizationResourceAbstractListView: def get_queryset(self): username = self.kwargs.get('user', None) @@ -249,15 +301,12 @@ def get_queryset(self): return self.queryset.filter(organization__in=user.organizations.all(), version=HEAD) - class OrganizationSourceListView(OrganizationResourceAbstractListView, SourceListView): pass - - + class OrganizationCollectionListView(OrganizationResourceAbstractListView, CollectionListView): pass - - + class OrganizationExtrasBaseView(APIView): def get_object(self): instance = Organization.objects.filter(is_active=True, mnemonic=self.kwargs['org']).first() @@ -265,18 +314,40 @@ def get_object(self): if not instance: raise Http404() return instance - - + class OrganizationExtrasView(OrganizationExtrasBaseView): serializer_class = OrganizationDetailSerializer + @swagger_auto_schema( + manual_parameters=[ + openapi.Parameter('org', openapi.IN_PATH, description="Organization mnemonic", type=openapi.TYPE_STRING, required=True), + ], + responses={ + status.HTTP_200_OK: openapi.Response( + description="Organization extras", + schema=openapi.Schema(type=openapi.TYPE_OBJECT, additional_properties=openapi.Schema(type=openapi.TYPE_STRING)) + ) + } + ) def get(self, request, org): # pylint: disable=unused-argument return Response(get(self.get_object(), 'extras', {})) - class OrganizationExtraRetrieveUpdateDestroyView(OrganizationExtrasBaseView, RetrieveUpdateDestroyAPIView): serializer_class = OrganizationDetailSerializer + @swagger_auto_schema( + manual_parameters=[ + openapi.Parameter('org', openapi.IN_PATH, description="Organization mnemonic", type=openapi.TYPE_STRING, required=True), + openapi.Parameter('extra', openapi.IN_PATH, description="Extra field key", type=openapi.TYPE_STRING, required=True), + ], + responses={ + status.HTTP_200_OK: openapi.Response( + description="Extra field value", + schema=openapi.Schema(type=openapi.TYPE_OBJECT, properties={'extra_key': openapi.Schema(type=openapi.TYPE_STRING)}) + ), + status.HTTP_404_NOT_FOUND: openapi.Response(description="Extra field not found") + } + ) def retrieve(self, request, *args, **kwargs): key = kwargs.get('extra') instance = self.get_object() @@ -286,6 +357,25 @@ def retrieve(self, request, *args, **kwargs): return Response({'detail': NOT_FOUND}, status=status.HTTP_404_NOT_FOUND) + @swagger_auto_schema( + manual_parameters=[ + openapi.Parameter('org', openapi.IN_PATH, description="Organization mnemonic", type=openapi.TYPE_STRING, required=True), + openapi.Parameter('extra', openapi.IN_PATH, description="Extra field key", type=openapi.TYPE_STRING, required=True), + ], + request_body=openapi.Schema( + type=openapi.TYPE_OBJECT, + properties={ + 'extra_key': openapi.Schema(type=openapi.TYPE_STRING, description="Value for the extra field") + } + ), + responses={ + status.HTTP_200_OK: openapi.Response( + description="Updated extra field", + schema=openapi.Schema(type=openapi.TYPE_OBJECT, properties={'extra_key': openapi.Schema(type=openapi.TYPE_STRING)}) + ), + status.HTTP_400_BAD_REQUEST: openapi.Response(description="Invalid input") + } + ) def update(self, request, **kwargs): # pylint: disable=arguments-differ key = kwargs.get('extra') value = request.data.get(key) @@ -299,6 +389,16 @@ def update(self, request, **kwargs): # pylint: disable=arguments-differ instance.set_checksums() return Response({key: value}) + @swagger_auto_schema( + manual_parameters=[ + openapi.Parameter('org', openapi.IN_PATH, description="Organization mnemonic", type=openapi.TYPE_STRING, required=True), + openapi.Parameter('extra', openapi.IN_PATH, description="Extra field key", type=openapi.TYPE_STRING, required=True), + ], + responses={ + status.HTTP_204_NO_CONTENT: openapi.Response(description="Extra field deleted"), + status.HTTP_404_NOT_FOUND: openapi.Response(description="Extra field not found") + } + ) def delete(self, request, *args, **kwargs): key = kwargs.get('extra') instance = self.get_object() From 740791d37f9bccf5be50b19202a954186525b9f0 Mon Sep 17 00:00:00 2001 From: West Onyinsi <40661440+WestOnyinsi@users.noreply.github.com> Date: Mon, 4 Nov 2024 18:58:07 +0300 Subject: [PATCH 2/5] Update views.py --- core/orgs/views.py | 100 ++++----------------------------------------- 1 file changed, 9 insertions(+), 91 deletions(-) diff --git a/core/orgs/views.py b/core/orgs/views.py index 37ee988e..9518126d 100644 --- a/core/orgs/views.py +++ b/core/orgs/views.py @@ -77,11 +77,12 @@ def get_serializer_class(self): @swagger_auto_schema( manual_parameters=[ - openapi.Parameter('user', openapi.IN_PATH, description="Filter by username", type=openapi.TYPE_STRING), openapi.Parameter(NO_MEMBERS, openapi.IN_QUERY, description="Filter organizations with no members", type=openapi.TYPE_BOOLEAN), - openapi.Parameter('updated_since', openapi.IN_QUERY, description="Filter by update date", type=openapi.TYPE_STRING, format=openapi.FORMAT_DATETIME), - openapi.Parameter(UPDATED_BY_USERNAME_PARAM, openapi.IN_QUERY, description="Filter by username of user who updated", type=openapi.TYPE_STRING), + openapi.Parameter('UPDATED_SINCE_PARAM', openapi.IN_QUERY, description="Filter by update date", type=openapi.TYPE_STRING, format=openapi.FORMAT_DATETIME), + openapi.Parameter(UPDATED_BY_USERNAME_PARAM, openapi.IN_QUERY, description="Filter Orgs by the update by user", type=openapi.TYPE_STRING), + openapi.Parameter('verbose', openapi.IN_QUERY, description="Include verbose details", type=openapi.TYPE_BOOLEAN, default=False), ], + responses={status.HTTP_200_OK: OrganizationListSerializer(many=True)} ) def get(self, request, *args, **kwargs): @@ -122,14 +123,6 @@ def get_permissions(self): return [CanViewConceptDictionary(), ] - @swagger_auto_schema( - manual_parameters=[ - openapi.Parameter('org', openapi.IN_PATH, description="Organization mnemonic", type=openapi.TYPE_STRING, required=True), - ], - responses={status.HTTP_200_OK: "Logo image"} - ) - def get(self, request, *args, **kwargs): - return super().get(request, *args, **kwargs) class OrganizationOverviewView(OrganizationBaseView, RetrieveAPIView, UpdateAPIView): serializer_class = OrganizationOverviewSerializer @@ -143,14 +136,6 @@ def get_permissions(self): def get_queryset(self): return super().get_queryset().filter(mnemonic=self.kwargs['org']) - @swagger_auto_schema( - manual_parameters=[ - openapi.Parameter('org', openapi.IN_PATH, description="Organization mnemonic", type=openapi.TYPE_STRING, required=True), - ], - responses={status.HTTP_200_OK: OrganizationOverviewSerializer()} - ) - def get(self, request, *args, **kwargs): - return super().get(request, *args, **kwargs) class OrganizationDetailView(OrganizationBaseView, mixins.UpdateModelMixin, mixins.CreateModelMixin, TaskMixin): def get_permissions(self): @@ -208,15 +193,7 @@ class OrganizationClientConfigsView(ResourceClientConfigsView): queryset = Organization.objects.filter(is_active=True) permission_classes = (CanViewConceptDictionary, ) - @swagger_auto_schema( - manual_parameters=[ - openapi.Parameter('org', openapi.IN_PATH, description="Organization mnemonic", type=openapi.TYPE_STRING, required=True), - ], - responses={status.HTTP_200_OK: "Client configs"} - ) - def get(self, request, *args, **kwargs): - return super().get(request, *args, **kwargs) - + class OrganizationMemberView(generics.GenericAPIView): userprofile = None user_in_org = False @@ -275,17 +252,7 @@ def delete(self, request, **kwargs): # pylint: disable=unused-argument return Response(status=status.HTTP_204_NO_CONTENT) - @swagger_auto_schema( - manual_parameters=[ - openapi.Parameter('org', openapi.IN_PATH, description="Organization mnemonic", type=openapi.TYPE_STRING, required=True), - openapi.Parameter('user', openapi.IN_PATH, description="Username", type=openapi.TYPE_STRING, required=True), - ], - responses={ - status.HTTP_204_NO_CONTENT: "User is a member", - status.HTTP_404_NOT_FOUND: "User is not a member", - status.HTTP_403_FORBIDDEN: "Permission denied" - } - ) + def get(self, request, *args, **kwargs): return super().get(request, *args, **kwargs) @@ -318,36 +285,13 @@ def get_object(self): class OrganizationExtrasView(OrganizationExtrasBaseView): serializer_class = OrganizationDetailSerializer - @swagger_auto_schema( - manual_parameters=[ - openapi.Parameter('org', openapi.IN_PATH, description="Organization mnemonic", type=openapi.TYPE_STRING, required=True), - ], - responses={ - status.HTTP_200_OK: openapi.Response( - description="Organization extras", - schema=openapi.Schema(type=openapi.TYPE_OBJECT, additional_properties=openapi.Schema(type=openapi.TYPE_STRING)) - ) - } - ) def get(self, request, org): # pylint: disable=unused-argument return Response(get(self.get_object(), 'extras', {})) class OrganizationExtraRetrieveUpdateDestroyView(OrganizationExtrasBaseView, RetrieveUpdateDestroyAPIView): serializer_class = OrganizationDetailSerializer - @swagger_auto_schema( - manual_parameters=[ - openapi.Parameter('org', openapi.IN_PATH, description="Organization mnemonic", type=openapi.TYPE_STRING, required=True), - openapi.Parameter('extra', openapi.IN_PATH, description="Extra field key", type=openapi.TYPE_STRING, required=True), - ], - responses={ - status.HTTP_200_OK: openapi.Response( - description="Extra field value", - schema=openapi.Schema(type=openapi.TYPE_OBJECT, properties={'extra_key': openapi.Schema(type=openapi.TYPE_STRING)}) - ), - status.HTTP_404_NOT_FOUND: openapi.Response(description="Extra field not found") - } - ) + def retrieve(self, request, *args, **kwargs): key = kwargs.get('extra') instance = self.get_object() @@ -357,24 +301,7 @@ def retrieve(self, request, *args, **kwargs): return Response({'detail': NOT_FOUND}, status=status.HTTP_404_NOT_FOUND) - @swagger_auto_schema( - manual_parameters=[ - openapi.Parameter('org', openapi.IN_PATH, description="Organization mnemonic", type=openapi.TYPE_STRING, required=True), - openapi.Parameter('extra', openapi.IN_PATH, description="Extra field key", type=openapi.TYPE_STRING, required=True), - ], - request_body=openapi.Schema( - type=openapi.TYPE_OBJECT, - properties={ - 'extra_key': openapi.Schema(type=openapi.TYPE_STRING, description="Value for the extra field") - } - ), - responses={ - status.HTTP_200_OK: openapi.Response( - description="Updated extra field", - schema=openapi.Schema(type=openapi.TYPE_OBJECT, properties={'extra_key': openapi.Schema(type=openapi.TYPE_STRING)}) - ), - status.HTTP_400_BAD_REQUEST: openapi.Response(description="Invalid input") - } + ) def update(self, request, **kwargs): # pylint: disable=arguments-differ key = kwargs.get('extra') @@ -389,16 +316,7 @@ def update(self, request, **kwargs): # pylint: disable=arguments-differ instance.set_checksums() return Response({key: value}) - @swagger_auto_schema( - manual_parameters=[ - openapi.Parameter('org', openapi.IN_PATH, description="Organization mnemonic", type=openapi.TYPE_STRING, required=True), - openapi.Parameter('extra', openapi.IN_PATH, description="Extra field key", type=openapi.TYPE_STRING, required=True), - ], - responses={ - status.HTTP_204_NO_CONTENT: openapi.Response(description="Extra field deleted"), - status.HTTP_404_NOT_FOUND: openapi.Response(description="Extra field not found") - } - ) + def delete(self, request, *args, **kwargs): key = kwargs.get('extra') instance = self.get_object() From 4e9f3ad5c2d6b2b462c08bd1fc630dd1907a32fd Mon Sep 17 00:00:00 2001 From: West Onyinsi <40661440+WestOnyinsi@users.noreply.github.com> Date: Tue, 5 Nov 2024 09:31:08 +0300 Subject: [PATCH 3/5] Update views.py --- core/orgs/views.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/core/orgs/views.py b/core/orgs/views.py index 9518126d..2702ac95 100644 --- a/core/orgs/views.py +++ b/core/orgs/views.py @@ -178,14 +178,6 @@ def destroy(self, request, *args, **kwargs): return Response(status=status.HTTP_204_NO_CONTENT) - @swagger_auto_schema( - manual_parameters=[ - openapi.Parameter('org', openapi.IN_PATH, description="Organization mnemonic", type=openapi.TYPE_STRING, required=True), - ], - responses={status.HTTP_200_OK: OrganizationDetailSerializer()} - ) - def get(self, request, *args, **kwargs): - return super().get(request, *args, **kwargs) class OrganizationClientConfigsView(ResourceClientConfigsView): lookup_field = 'org' From f0718ce2e6e25c4f6468e895ebc643ab5950d3d1 Mon Sep 17 00:00:00 2001 From: West Onyinsi <40661440+WestOnyinsi@users.noreply.github.com> Date: Tue, 5 Nov 2024 12:21:55 +0300 Subject: [PATCH 4/5] Update views.py --- core/orgs/views.py | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/core/orgs/views.py b/core/orgs/views.py index 2702ac95..63d00e04 100644 --- a/core/orgs/views.py +++ b/core/orgs/views.py @@ -184,8 +184,7 @@ class OrganizationClientConfigsView(ResourceClientConfigsView): model = Organization queryset = Organization.objects.filter(is_active=True) permission_classes = (CanViewConceptDictionary, ) - - + class OrganizationMemberView(generics.GenericAPIView): userprofile = None user_in_org = False @@ -242,11 +241,6 @@ def delete(self, request, **kwargs): # pylint: disable=unused-argument self.userprofile.save() return Response(status=status.HTTP_204_NO_CONTENT) - - - - def get(self, request, *args, **kwargs): - return super().get(request, *args, **kwargs) class OrganizationResourceAbstractListView: def get_queryset(self): @@ -294,7 +288,6 @@ def retrieve(self, request, *args, **kwargs): return Response({'detail': NOT_FOUND}, status=status.HTTP_404_NOT_FOUND) - ) def update(self, request, **kwargs): # pylint: disable=arguments-differ key = kwargs.get('extra') value = request.data.get(key) @@ -308,7 +301,6 @@ def update(self, request, **kwargs): # pylint: disable=arguments-differ instance.set_checksums() return Response({key: value}) - def delete(self, request, *args, **kwargs): key = kwargs.get('extra') instance = self.get_object() From 31d0d4def68348905717350ffa0425a7dc090b78 Mon Sep 17 00:00:00 2001 From: West Onyinsi <40661440+WestOnyinsi@users.noreply.github.com> Date: Tue, 5 Nov 2024 12:37:04 +0300 Subject: [PATCH 5/5] Update views.py --- core/orgs/views.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/core/orgs/views.py b/core/orgs/views.py index 63d00e04..be5fe1aa 100644 --- a/core/orgs/views.py +++ b/core/orgs/views.py @@ -184,7 +184,8 @@ class OrganizationClientConfigsView(ResourceClientConfigsView): model = Organization queryset = Organization.objects.filter(is_active=True) permission_classes = (CanViewConceptDictionary, ) - + + class OrganizationMemberView(generics.GenericAPIView): userprofile = None user_in_org = False @@ -231,6 +232,7 @@ def put(self, request, **kwargs): # pylint: disable=unused-argument return Response(status=status.HTTP_204_NO_CONTENT) + def delete(self, request, **kwargs): # pylint: disable=unused-argument if not request.user.is_staff and not self.user_in_org: return Response(status=status.HTTP_403_FORBIDDEN) @@ -254,12 +256,14 @@ def get_queryset(self): return self.queryset.filter(organization__in=user.organizations.all(), version=HEAD) + class OrganizationSourceListView(OrganizationResourceAbstractListView, SourceListView): pass class OrganizationCollectionListView(OrganizationResourceAbstractListView, CollectionListView): pass - + + class OrganizationExtrasBaseView(APIView): def get_object(self): instance = Organization.objects.filter(is_active=True, mnemonic=self.kwargs['org']).first() @@ -267,17 +271,18 @@ def get_object(self): if not instance: raise Http404() return instance - + + class OrganizationExtrasView(OrganizationExtrasBaseView): serializer_class = OrganizationDetailSerializer def get(self, request, org): # pylint: disable=unused-argument return Response(get(self.get_object(), 'extras', {})) + class OrganizationExtraRetrieveUpdateDestroyView(OrganizationExtrasBaseView, RetrieveUpdateDestroyAPIView): serializer_class = OrganizationDetailSerializer - def retrieve(self, request, *args, **kwargs): key = kwargs.get('extra') instance = self.get_object()