Allow modifying those fields that are not directly derived from the
mbox. The complication is that PATCH and POST now support a different
set of fields (POST allows writing arbitrary data to the message) so
we need to use get_serializer_class() instead of the simpler
serializer_class.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
api/rest.py | 52 +++++++++++++++++++++++++++++++++-------------
tests/test_rest.py | 32 ++++++++++++++++++++++++++++
2 files changed, 70 insertions(+), 14 deletions(-)
diff --git a/api/rest.py b/api/rest.py
index 1bd637d..3b6ab2f 100644
--- a/api/rest.py
+++ b/api/rest.py
@@ -22,9 +22,10 @@ from rest_framework.decorators import action
from rest_framework.fields import SerializerMethodField, CharField, JSONField, EmailField, ListField
from rest_framework.relations import HyperlinkedIdentityField
from rest_framework.response import Response
+from rest_framework.views import APIView
import rest_framework
from mbox import addr_db_to_rest, MboxMessage
-from rest_framework.parsers import JSONParser, BaseParser
+from rest_framework.parsers import BaseParser
SEARCH_PARAM = 'q'
@@ -274,7 +275,8 @@ class AddressSerializer(serializers.Serializer):
class BaseMessageSerializer(serializers.ModelSerializer):
class Meta:
model = Message
- fields = ('resource_uri', 'message_id', 'subject', 'date', 'sender', 'recipients', 'tags')
+ read_only_fields = ('resource_uri', 'message_id', 'subject', 'date', 'sender', 'recipients')
+ fields = read_only_fields + ('tags', )
resource_uri = HyperlinkedMessageField(view_name='messages-detail')
recipients = AddressSerializer(many=True)
@@ -300,7 +302,7 @@ class BaseMessageViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
# a (project, message_id) tuple is unique, so we can always retrieve an object
-class ProjectMessagesViewSetMixin(mixins.RetrieveModelMixin):
+class ProjectMessagesViewSetMixin(mixins.RetrieveModelMixin, mixins.UpdateModelMixin):
def get_queryset(self):
return self.queryset.filter(project=self.kwargs['projects_pk'])
@@ -342,10 +344,12 @@ class PatchSerializer(BaseMessageSerializer):
class SeriesSerializer(BaseMessageSerializer):
class Meta:
model = Message
- fields = ('resource_uri',) + BaseMessageSerializer.Meta.fields + (
- 'message', 'stripped_subject', 'last_comment_date', 'last_reply_date',
- 'is_complete', 'is_merged', 'num_patches', 'total_patches', 'results',
+ subclass_read_only_fields = ('message', 'stripped_subject', 'num_patches',
+ 'total_patches', 'results')
+ fields = BaseMessageSerializer.Meta.fields + subclass_read_only_fields + (
+ 'last_comment_date', 'last_reply_date', 'is_complete', 'is_merged',
'is_obsolete', 'is_tested', 'is_reviewed', 'maintainers')
+ read_only_fields = BaseMessageSerializer.Meta.read_only_fields + subclass_read_only_fields
resource_uri = HyperlinkedMessageField(view_name='series-detail')
message = HyperlinkedMessageField(view_name='messages-detail')
@@ -416,7 +420,8 @@ class SeriesViewSet(BaseMessageViewSet):
class ProjectSeriesViewSet(ProjectMessagesViewSetMixin,
- SeriesViewSet, mixins.DestroyModelMixin):
+ SeriesViewSet, mixins.UpdateModelMixin,
+ mixins.DestroyModelMixin):
def collect_patches(self, series):
if series.is_patch:
patches = [series]
@@ -456,11 +461,12 @@ class ProjectSeriesViewSet(ProjectMessagesViewSetMixin,
# Messages
-# TODO: add POST endpoint connected to email plugin?
class MessageSerializer(BaseMessageSerializer):
class Meta:
model = Message
fields = BaseMessageSerializer.Meta.fields + ('mbox', )
+ read_only_fields = BaseMessageSerializer.Meta.read_only_fields + ('mbox', )
+
mbox = CharField()
def get_fields(self):
@@ -476,6 +482,14 @@ class MessageSerializer(BaseMessageSerializer):
return fields
+class MessageCreationSerializer(BaseMessageSerializer):
+ class Meta:
+ model = Message
+ fields = BaseMessageSerializer.Meta.fields + ('mbox', )
+ read_only_fields = []
+
+ mbox = CharField()
+
class StaticTextRenderer(renderers.BaseRenderer):
media_type = 'text/plain'
format = 'mbox'
@@ -497,10 +511,15 @@ class MessagePlainTextParser(BaseParser):
return MboxMessage(data).get_json()
-class ProjectMessagesViewSet(ProjectMessagesViewSetMixin,
- BaseMessageViewSet, mixins.CreateModelMixin):
- serializer_class = MessageSerializer
- parser_classes = (JSONParser, MessagePlainTextParser, )
+class ProjectMessagesViewSet(ProjectMessagesViewSetMixin, BaseMessageViewSet,
+ mixins.CreateModelMixin, mixins.UpdateModelMixin):
+ parser_classes = APIView.parser_classes + [MessagePlainTextParser]
+
+ def get_serializer_class(self, *args, **kwargs):
+ if self.request.method == 'POST':
+ return MessageCreationSerializer
+ else:
+ return MessageSerializer
@action(detail=True, renderer_classes=[StaticTextRenderer])
def mbox(self, request, *args, **kwargs):
@@ -519,9 +538,14 @@ class ProjectMessagesViewSet(ProjectMessagesViewSetMixin,
class MessagesViewSet(BaseMessageViewSet):
- serializer_class = MessageSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
- parser_classes = (JSONParser, MessagePlainTextParser, )
+ parser_classes = APIView.parser_classes + [MessagePlainTextParser]
+
+ def get_serializer_class(self, *args, **kwargs):
+ if self.request.method == 'POST':
+ return MessageCreationSerializer
+ else:
+ return MessageSerializer
def create(self, request, *args, **kwargs):
m = MboxMessage(request.data['mbox'])
diff --git a/tests/test_rest.py b/tests/test_rest.py
index dd38035..d6cbf62 100755
--- a/tests/test_rest.py
+++ b/tests/test_rest.py
@@ -353,6 +353,24 @@ class RestTest(PatchewTestCase):
self.assertEqual(resp.data['subject'], "[Qemu-devel] [PATCH v2 10/27] imx_fec: Reserve full 4K "
"page for the register file")
+ def test_patch_message(self):
+ the_tags = ['Reviewed-by: Paolo Bonzini <pbonzini@redhat.com']
+ dp = self.get_data_path("0022-another-simple-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.PROJECT_BASE + "messages/", data, content_type='application/json')
+ self.assertEqual(resp.status_code, 201)
+ resp_get = self.api_client.get(self.PROJECT_BASE + "messages/20171023201055.21973-11-andrew.smirnov@gmail.com/")
+ self.assertEqual(resp_get.status_code, 200)
+ self.assertEqual(resp_get.data['tags'], [])
+ resp = self.api_client.patch(self.PROJECT_BASE + "messages/20171023201055.21973-11-andrew.smirnov@gmail.com/",
+ { 'tags': the_tags })
+ self.assertEqual(resp.status_code, 200)
+ resp_get = self.api_client.get(self.PROJECT_BASE + "messages/20171023201055.21973-11-andrew.smirnov@gmail.com/")
+ self.assertEqual(resp_get.status_code, 200)
+ self.assertEqual(resp_get.data['tags'], the_tags)
+
def test_create_text_message(self):
dp = self.get_data_path("0004-multiple-patch-reviewed.mbox.gz")
with open(dp, "r") as f:
@@ -364,6 +382,20 @@ 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_patch_series(self):
+ dp = self.get_data_path("0001-simple-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.PROJECT_BASE + "messages/", data, content_type='message/rfc822')
+ self.assertEqual(resp.status_code, 201)
+ resp = self.api_client.patch(self.PROJECT_BASE + "series/20160628014747.20971-1-famz@redhat.com/",
+ { 'is_tested' : True })
+ self.assertEqual(resp.status_code, 200)
+ resp_get = self.api_client.get(self.PROJECT_BASE + "series/20160628014747.20971-1-famz@redhat.com/")
+ self.assertEqual(resp_get.status_code, 200)
+ self.assertTrue(resp_get.data['is_tested'])
+
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:
--
2.21.0
_______________________________________________
Patchew-devel mailing list
Patchew-devel@redhat.com
https://www.redhat.com/mailman/listinfo/patchew-devel
© 2016 - 2025 Red Hat, Inc.