[Patchew-devel] [PATCH] rest: add api/v1/messages endpoint (POST support)

Shubham Jain posted 1 patch 5 years, 10 months ago
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/patchew-ci tags/patchew/20180515092625.43888-1-shubhamjain7495@gmail.com
There is a newer version of this series
api/rest.py                                    |  22 +++++++++--
api/urls.py                                    |   3 +-
tests/data/0023-multiple-project-patch.mbox.gz | Bin 0 -> 2274 bytes
tests/data/0024-multiple-project-patch.json.gz | Bin 0 -> 2471 bytes
tests/test_rest.py                             |  51 ++++++++++++++++++++++++-
5 files changed, 70 insertions(+), 6 deletions(-)
create mode 100644 tests/data/0023-multiple-project-patch.mbox.gz
create mode 100644 tests/data/0024-multiple-project-patch.json.gz
[Patchew-devel] [PATCH] rest: add api/v1/messages endpoint (POST support)
Posted by Shubham Jain 5 years, 10 months ago
To apply a single message to the project according to the group user is from. For importer user, message is added to all recognised project. For other users, message is added to all the projects recognised and maintained by the user.
---
 api/rest.py                                    |  22 +++++++++--
 api/urls.py                                    |   3 +-
 tests/data/0023-multiple-project-patch.mbox.gz | Bin 0 -> 2274 bytes
 tests/data/0024-multiple-project-patch.json.gz | Bin 0 -> 2471 bytes
 tests/test_rest.py                             |  51 ++++++++++++++++++++++++-
 5 files changed, 70 insertions(+), 6 deletions(-)
 create mode 100644 tests/data/0023-multiple-project-patch.mbox.gz
 create mode 100644 tests/data/0024-multiple-project-patch.json.gz

diff --git a/api/rest.py b/api/rest.py
index 1f81fe7..6264085 100644
--- a/api/rest.py
+++ b/api/rest.py
@@ -17,7 +17,7 @@ from mod import dispatch_module_hook
 from .models import Project, Message
 from .search import SearchEngine
 from rest_framework import (permissions, serializers, viewsets, filters,
-    mixins, generics, renderers)
+    mixins, generics, renderers, status)
 from rest_framework.decorators import detail_route
 from rest_framework.fields import SerializerMethodField, CharField, JSONField, EmailField
 from rest_framework.relations import HyperlinkedIdentityField
@@ -162,7 +162,6 @@ class AddressSerializer(serializers.Serializer):
         except:
             return [validated_data['address'], validated_data['address']]
 
-
 class BaseMessageSerializer(serializers.ModelSerializer):
     class Meta:
         model = Message
@@ -288,7 +287,6 @@ class SeriesViewSet(BaseMessageViewSet):
     filter_backends = (PatchewSearchFilter,)
     search_fields = (SEARCH_PARAM,)
 
-
 class ProjectSeriesViewSet(ProjectMessagesViewSetMixin,
                            SeriesViewSet, mixins.DestroyModelMixin):
     def collect_patches(self, series):
@@ -368,7 +366,7 @@ class MessagePlainTextParser(BaseParser):
         data = stream.read().decode("utf-8")
         return MboxMessage(data).get_json()
 
-class MessagesViewSet(ProjectMessagesViewSetMixin,
+class ProjectMessagesViewSet(ProjectMessagesViewSetMixin,
                       BaseMessageViewSet, mixins.CreateModelMixin):
     serializer_class = MessageSerializer
     parser_classes = (JSONParser, MessagePlainTextParser, )
@@ -388,6 +386,22 @@ class MessagesViewSet(ProjectMessagesViewSetMixin,
                                            context=self.get_serializer_context())
         return self.get_paginated_response(serializer.data)
 
+class MessagesViewSet(BaseMessageViewSet):
+    serializer_class = MessageSerializer
+    parser_classes = (JSONParser, MessagePlainTextParser, )
+    
+    def create(self, request, *args, **kwargs):
+        projects = [p for p in Project.objects.all() if p.recognizes(MboxMessage(self.request.data['mbox']))]
+
+        if 'importers' not in self.request.user.groups.all():
+            projects = set(projects) & set([p for p in Project.objects.all() if p.maintained_by(self.request.user)])
+        for project in projects:
+            request.data['project'] = project
+            serializer = MessageSerializer(data=request.data,context={'project': project, 'request': self.request})
+            serializer.is_valid(raise_exception=True)
+            serializer.save()
+        return Response("Sucess", status=status.HTTP_201_CREATED)
+
 # Results
 
 class HyperlinkedResultField(HyperlinkedIdentityField):
diff --git a/api/urls.py b/api/urls.py
index 64e9629..2fd4e0f 100644
--- a/api/urls.py
+++ b/api/urls.py
@@ -31,12 +31,13 @@ router.include_format_suffixes = False
 router.register('users', rest.UsersViewSet)
 router.register('projects', rest.ProjectsViewSet)
 router.register('series', rest.SeriesViewSet, base_name='series')
+router.register('messages', rest.MessagesViewSet)
 
 projects_router = NestedDefaultRouter(router, 'projects', lookup='projects', trailing_slash=True)
 projects_router.include_format_suffixes = False
 projects_router.register('results', rest.ProjectResultsViewSet, base_name='results')
 projects_router.register('series', rest.ProjectSeriesViewSet, base_name='series')
-projects_router.register('messages', rest.MessagesViewSet, base_name='messages')
+projects_router.register('messages', rest.ProjectMessagesViewSet, base_name='messages')
 
 results_router = NestedDefaultRouter(projects_router, 'series', lookup='series', trailing_slash=True)
 results_router.include_format_suffixes = False
diff --git a/tests/data/0023-multiple-project-patch.mbox.gz b/tests/data/0023-multiple-project-patch.mbox.gz
new file mode 100644
index 0000000000000000000000000000000000000000..6d63736020c35a523cdef327a3022c759c941436
GIT binary patch
literal 2274
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

literal 0
HcmV?d00001

diff --git a/tests/data/0024-multiple-project-patch.json.gz b/tests/data/0024-multiple-project-patch.json.gz
new file mode 100644
index 0000000000000000000000000000000000000000..2866b7fbac5a2fc5607b723dbd3d125a7dca4b7c
GIT binary patch
literal 2471
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

literal 0
HcmV?d00001

diff --git a/tests/test_rest.py b/tests/test_rest.py
index 7896e8a..9fd9ed9 100755
--- a/tests/test_rest.py
+++ b/tests/test_rest.py
@@ -37,6 +37,8 @@ class RestTest(PatchewTestCase):
         self.sp.prefix_tags = "block"
         self.sp.save()
         self.SUBPROJECT_BASE = '%sprojects/%d/' % (self.REST_BASE, self.sp.id)
+        self.p2 = self.add_project("EDK 2", "edk2-devel@lists.01.org")
+        self.PROJECT_BASE_2 = '%sprojects/%d/' % (self.REST_BASE, self.p2.id)
 
         self.admin = User.objects.get(username='admin')
         self.USER_BASE = '%susers/%d/' % (self.REST_BASE, self.admin.id)
@@ -64,7 +66,7 @@ class RestTest(PatchewTestCase):
 
     def test_projects(self):
         resp = self.api_client.get(self.REST_BASE + 'projects/')
-        self.assertEquals(resp.data['count'], 2)
+        self.assertEquals(resp.data['count'], 3)
         self.assertEquals(resp.data['results'][0]['resource_uri'], self.PROJECT_BASE)
         self.assertEquals(resp.data['results'][0]['name'], "QEMU")
         self.assertEquals(resp.data['results'][0]['mailing_list'], "qemu-devel@nongnu.org")
@@ -295,6 +297,32 @@ class RestTest(PatchewTestCase):
         self.assertEqual(resp_get.status_code, 200)
         self.assertEqual(resp.data['subject'], "[Qemu-devel] [PATCH v4 0/2] Report format specific info for LUKS block driver")
 
+    def test_create_message_without_project_pk(self):
+        dp = self.get_data_path("0024-multiple-project-patch.json.gz")
+        with open(dp, "r") as f:
+            data = f.read()
+        self.api_client.login(username=self.user, password=self.password)
+        resp = self.api_client.post(self.REST_BASE + "messages/", data, content_type='application/json')
+        self.assertEqual(resp.status_code, 201)
+        self.assertEqual(resp.data, "Sucess")
+        resp_get = self.api_client.get(self.PROJECT_BASE + "messages/20180223132311.26555-2-marcandre.lureau@redhat.com/")
+        self.assertEqual(resp_get.status_code, 200)
+        self.assertEqual(resp_get.data['subject'], "[Qemu-devel] [PATCH 1/7] SecurityPkg/Tcg2Pei: drop Tcg2PhysicalPresenceLib dependency")
+        resp_get2 = self.api_client.get(self.PROJECT_BASE_2 + "messages/20180223132311.26555-2-marcandre.lureau@redhat.com/")
+        
+    def test_create_text_message_without_project_pk(self):
+        dp = self.get_data_path("0023-multiple-project-patch.mbox.gz")
+        with open(dp, "r") as f:
+            data = f.read()
+        self.api_client.login(username=self.user, password=self.password)
+        resp = self.api_client.post(self.REST_BASE + "messages/", data, content_type='message/rfc822')
+        self.assertEqual(resp.status_code, 201)
+        self.assertEqual(resp.data, "Sucess")
+        resp_get = self.api_client.get(self.PROJECT_BASE + "messages/20180223132311.26555-2-marcandre.lureau@redhat.com/")
+        self.assertEqual(resp_get.status_code, 200)
+        self.assertEqual(resp_get.data['subject'], "[Qemu-devel] [PATCH 1/7] SecurityPkg/Tcg2Pei: drop Tcg2PhysicalPresenceLib dependency")
+        resp_get2 = self.api_client.get(self.PROJECT_BASE_2 + "messages/20180223132311.26555-2-marcandre.lureau@redhat.com/")
+
     def test_message(self):
         series = self.apply_and_retrieve('0001-simple-patch.mbox.gz',
                                          self.p.id, '20160628014747.20971-1-famz@redhat.com')
@@ -346,5 +374,26 @@ class RestTest(PatchewTestCase):
         resp = self.api_client.get(self.REST_BASE + 'schema/')
         self.assertEqual(resp.status_code, 200)
 
+    # def test_create_message_without_project_pk(self):
+    #     dp = self.get_data_path("multiple-project-patch.json.gz")
+    #     with open(dp, "r") as f:
+    #         data = f.read()
+    #     self.api_client.login(username=self.user, password=self.password)
+    #     resp = self.api_client.post(self.REST_BASE + "messages/", data, content_type='application/json')
+    #     print(resp.data)
+    #     self.assertEqual(resp.status_code, 201)
+    #     resp_get = self.api_client.get(self.PROJECT_BASE + "messages/20180223132311.26555-2-marcandre.lureau@redhat.com/")
+    #     self.assertEqual(resp_get.status_code, 200)
+    #     self.assertEqual(resp.data['subject'], "[Qemu-devel] [PATCH 1/7] SecurityPkg/Tcg2Pei: drop Tcg2PhysicalPresenceLib dependency")
+
+    # def test_create_text_message_without_project_pk(self):
+        # ? print(resp.data)
+
+    #     self.assertEqual(resp.status_code, 201)
+    #     resp_get = self.api_client.get(self.PROJECT_BASE + "messages/20180223132311.26555-2-marcandre.lureau@redhat.com/")
+    #     self.assertEqual(resp_get.status_code, 200)
+    #     self.assertEqual(resp.data['subject'], "[Qemu-devel] [PATCH 1/7] SecurityPkg/Tcg2Pei: drop Tcg2PhysicalPresenceLib dependency")
+
+
 if __name__ == '__main__':
     main()
-- 
2.14.3 (Apple Git-98)

_______________________________________________
Patchew-devel mailing list
Patchew-devel@redhat.com
https://www.redhat.com/mailman/listinfo/patchew-devel
Re: [Patchew-devel] [PATCH] rest: add api/v1/messages endpoint (POST support)
Posted by Shubham Jain 5 years, 10 months ago
Apparently calling only save in loop is leading to update. So overrode the
create() and it works.

+    def test_create_message_without_project_pk(self):
> +        dp = self.get_data_path("0024-multiple-project-patch.json.gz")
> +        with open(dp, "r") as f:
> +            data = f.read()
> +        self.api_client.login(username=self.user, password=self.password)
> +        resp = self.api_client.post(self.REST_BASE + "messages/", data,
> content_type='application/json')
> +        self.assertEqual(resp.status_code, 201)
> +        self.assertEqual(resp.data, "Sucess")
> +        resp_get = self.api_client.get(self.PROJECT_BASE + "messages/
> 20180223132311.26555-2-marcandre.lureau@redhat.com/")
> +        self.assertEqual(resp_get.status_code, 200)
> +        self.assertEqual(resp_get.data['subject'], "[Qemu-devel] [PATCH
> 1/7] SecurityPkg/Tcg2Pei: drop Tcg2PhysicalPresenceLib dependency")
> +        resp_get2 = self.api_client.get(self.PROJECT_BASE_2 + "messages/
> 20180223132311.26555-2-marcandre.lureau@redhat.com/")
> +
> +    def test_create_text_message_without_project_pk(self):
> +        dp = self.get_data_path("0023-multiple-project-patch.mbox.gz")
> +        with open(dp, "r") as f:
> +            data = f.read()
> +        self.api_client.login(username=self.user, password=self.password)
> +        resp = self.api_client.post(self.REST_BASE + "messages/", data,
> content_type='message/rfc822')
> +        self.assertEqual(resp.status_code, 201)
> +        self.assertEqual(resp.data, "Sucess")
> +        resp_get = self.api_client.get(self.PROJECT_BASE + "messages/
> 20180223132311.26555-2-marcandre.lureau@redhat.com/")
> +        self.assertEqual(resp_get.status_code, 200)
> +        self.assertEqual(resp_get.data['subject'], "[Qemu-devel] [PATCH
> 1/7] SecurityPkg/Tcg2Pei: drop Tcg2PhysicalPresenceLib dependency")
> +        resp_get2 = self.api_client.get(self.PROJECT_BASE_2 + "messages/
> 20180223132311.26555-2-marcandre.lureau@redhat.com/")
> +
>      def test_message(self):
>          series = self.apply_and_retrieve('0001-simple-patch.mbox.gz',
>                                           self.p.id, '
> 20160628014747.20971-1-famz@redhat.com')
> @@ -346,5 +374,26 @@ class RestTest(PatchewTestCase):
>          resp = self.api_client.get(self.REST_BASE + 'schema/')
>          self.assertEqual(resp.status_code, 200)
>
> +    # def test_create_message_without_project_pk(self):
> +    #     dp = self.get_data_path("multiple-project-patch.json.gz")
> +    #     with open(dp, "r") as f:
> +    #         data = f.read()
> +    #     self.api_client.login(username=self.user,
> password=self.password)
> +    #     resp = self.api_client.post(self.REST_BASE + "messages/", data,
> content_type='application/json')
> +    #     print(resp.data)
> +    #     self.assertEqual(resp.status_code, 201)
> +    #     resp_get = self.api_client.get(self.PROJECT_BASE + "messages/
> 20180223132311.26555-2-marcandre.lureau@redhat.com/")
> +    #     self.assertEqual(resp_get.status_code, 200)
> +    #     self.assertEqual(resp.data['subject'], "[Qemu-devel] [PATCH
> 1/7] SecurityPkg/Tcg2Pei: drop Tcg2PhysicalPresenceLib dependency")
> +
> +    # def test_create_text_message_without_project_pk(self):
> +        # ? print(resp.data)
> +
> +    #     self.assertEqual(resp.status_code, 201)
> +    #     resp_get = self.api_client.get(self.PROJECT_BASE + "messages/
> 20180223132311.26555-2-marcandre.lureau@redhat.com/")
> +    #     self.assertEqual(resp_get.status_code, 200)
> +    #     self.assertEqual(resp.data['subject'], "[Qemu-devel] [PATCH
> 1/7] SecurityPkg/Tcg2Pei: drop Tcg2PhysicalPresenceLib dependency")
> +
> +
>
Ignore this, will correct it.

>  if __name__ == '__main__':
>      main()
> --
> 2.14.3 (Apple Git-98)
>
>
_______________________________________________
Patchew-devel mailing list
Patchew-devel@redhat.com
https://www.redhat.com/mailman/listinfo/patchew-devel
Re: [Patchew-devel] [PATCH] rest: add api/v1/messages endpoint (POST support)
Posted by Paolo Bonzini 5 years, 10 months ago
On 15/05/2018 11:26, Shubham Jain wrote:
> To apply a single message to the project according to the group user is from. For importer user, message is added to all recognised project. For other users, message is added to all the projects recognised and maintained by the user.
> ---
>  api/rest.py                                    |  22 +++++++++--
>  api/urls.py                                    |   3 +-
>  tests/data/0023-multiple-project-patch.mbox.gz | Bin 0 -> 2274 bytes
>  tests/data/0024-multiple-project-patch.json.gz | Bin 0 -> 2471 bytes
>  tests/test_rest.py                             |  51 ++++++++++++++++++++++++-
>  5 files changed, 70 insertions(+), 6 deletions(-)
>  create mode 100644 tests/data/0023-multiple-project-patch.mbox.gz
>  create mode 100644 tests/data/0024-multiple-project-patch.json.gz
> 
> diff --git a/api/rest.py b/api/rest.py
> index 1f81fe7..6264085 100644
> --- a/api/rest.py
> +++ b/api/rest.py
> @@ -17,7 +17,7 @@ from mod import dispatch_module_hook
>  from .models import Project, Message
>  from .search import SearchEngine
>  from rest_framework import (permissions, serializers, viewsets, filters,
> -    mixins, generics, renderers)
> +    mixins, generics, renderers, status)
>  from rest_framework.decorators import detail_route
>  from rest_framework.fields import SerializerMethodField, CharField, JSONField, EmailField
>  from rest_framework.relations import HyperlinkedIdentityField
> @@ -162,7 +162,6 @@ class AddressSerializer(serializers.Serializer):
>          except:
>              return [validated_data['address'], validated_data['address']]
>  
> -
>  class BaseMessageSerializer(serializers.ModelSerializer):
>      class Meta:
>          model = Message
> @@ -288,7 +287,6 @@ class SeriesViewSet(BaseMessageViewSet):
>      filter_backends = (PatchewSearchFilter,)
>      search_fields = (SEARCH_PARAM,)
>  
> -
>  class ProjectSeriesViewSet(ProjectMessagesViewSetMixin,
>                             SeriesViewSet, mixins.DestroyModelMixin):
>      def collect_patches(self, series):
> @@ -368,7 +366,7 @@ class MessagePlainTextParser(BaseParser):
>          data = stream.read().decode("utf-8")
>          return MboxMessage(data).get_json()
>  
> -class MessagesViewSet(ProjectMessagesViewSetMixin,
> +class ProjectMessagesViewSet(ProjectMessagesViewSetMixin,
>                        BaseMessageViewSet, mixins.CreateModelMixin):
>      serializer_class = MessageSerializer
>      parser_classes = (JSONParser, MessagePlainTextParser, )
> @@ -388,6 +386,22 @@ class MessagesViewSet(ProjectMessagesViewSetMixin,
>                                             context=self.get_serializer_context())
>          return self.get_paginated_response(serializer.data)
>  
> +class MessagesViewSet(BaseMessageViewSet):
> +    serializer_class = MessageSerializer
> +    parser_classes = (JSONParser, MessagePlainTextParser, )
> +    
> +    def create(self, request, *args, **kwargs):
> +        projects = [p for p in Project.objects.all() if p.recognizes(MboxMessage(self.request.data['mbox']))]
> +
> +        if 'importers' not in self.request.user.groups.all():
> +            projects = set(projects) & set([p for p in Project.objects.all() if p.maintained_by(self.request.user)])
> +        for project in projects:
> +            request.data['project'] = project

Is this line still needed?


> +            serializer = MessageSerializer(data=request.data,context={'project': project, 'request': self.request})

You can also do

	serializer = self.get_serializer(data=request.data)
	serializer.is_valid(raise_exception=True)
	serializer.save(project=project)

It is a bit longer (you need to keep the older change to support
request.data['project']), but perhaps cleaner because you reuse
GenericViewSet's code to create the serializer and the context.

> +            serializer.is_valid(raise_exception=True)
> +            serializer.save()
> +        return Response("Sucess", status=status.HTTP_201_CREATED)

The response should include all the serializer's data.  You can do
something similar to ResultsViewSet:

        results = []
        ...
        for project in projects:
            ...
            results.append(serializer.data)
        return Response(OrderedDict([
            ('count', len(results)),
            ('results', results)
        ]), status=status.HTTP_201_CREATED)


Thanks,

Paolo

> +
>  # Results

_______________________________________________
Patchew-devel mailing list
Patchew-devel@redhat.com
https://www.redhat.com/mailman/listinfo/patchew-devel