<div dir="ltr"><br><br><div class="gmail_quote"><div dir="ltr">On Mon, May 7, 2018 at 4:25 PM Paolo Bonzini <<a href="mailto:pbonzini@redhat.com">pbonzini@redhat.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">On 05/05/2018 09:09, Shubham Jain wrote:<br>
> This commit allows to create/POST message from browser<br>
> - Add "create" method to MessageManager so that it calls save_mbox()<br>
> - Add getter and setter for mbox<br>
> - Rename the existing "mbox" field to e.g. "mbox_blob"<br>
> - Fix nested writable serializer issue<br>
<br>
This already looks pretty good, but:<br>
<br>
- there are no test cases<br></blockquote><div><br></div><div>I was thinking of doing this when we have POST for both json and text/plain format. </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
- we should use it as an exercise in posting a series composed of<br>
multiple changes<br></blockquote><div> </div><div>I still don't know how to send the multiple patches in a single patch. </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
- I have a few small comments below on the code.<br>
<br>
If you feel more confident sending everything as a single patch first,<br>
and still without tests (that is with only the code comments addressed),<br>
that's fine for me.<br>
<br>
Now, on to the code.<br>
<br>
> ---<br>
> api/models.py | 39 +++++++++++++++++++++++++++++++--------<br>
> api/rest.py | 20 +++++++++++---------<br>
> 2 files changed, 42 insertions(+), 17 deletions(-)<br>
> <br>
> diff --git a/api/models.py b/api/models.py<br>
> index 504f2c7..43b1037 100644<br>
> --- a/api/models.py<br>
> +++ b/api/models.py<br>
> @@ -247,6 +247,24 @@ class MessageManager(models.Manager):<br>
> self.delete_subthread(r)<br>
> msg.delete()<br>
> <br>
> + def create(self,project, **validated_data):<br>
> + mbox = validated_data.pop('mbox')<br>
> + m = MboxMessage(mbox)<br>
> + msg = Message(**validated_data)<br>
> + msg.in_reply_to = m.get_in_reply_to() or ""<br>
<br>
Setting in_reply_to here is the right thing to do for how the code<br>
behaves right now. However, the real problem is that it's missing in<br>
MessageSerializer! Can you add it, and here do:<br>
<br>
if 'in_reply_to' not in validated_data:<br>
msg.in_reply_to = m.get_in_reply_to() or ""<br>
<br>
?<br></blockquote><div>Yeah, this makes more sense. </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
> + msg.stripped_subject = m.get_subject(strip_tags=True)<br>
> + msg.version = m.get_version()<br>
> + msg.prefixes = m.get_prefixes()<br>
> + msg.is_series_head = m.is_series_head()<br>
> + msg.is_patch = m.is_patch()<br>
> + msg.patch_num = m.get_num()[0]<br>
> + msg.project = project<br>
> + msg.mbox = mbox<br>
> + msg.save_mbox(mbox)<br>
> + msg.save()<br>
> + emit_event("MessageAdded", message=msg)<br>
> + return msg<br>
> +<br>
> def add_message_from_mbox(self, mbox, user, project_name=None):<br>
> <br>
> def find_message_projects(m):<br>
> @@ -321,20 +339,25 @@ class Message(models.Model):<br>
> <br>
> objects = MessageManager()<br>
> <br>
> - def save_mbox(self, mbox):<br>
> - save_blob(mbox, self.message_id)<br>
> + def save_mbox(self, mbox_blob):<br>
> + save_blob(mbox_blob, self.message_id)<br>
> <br>
> def get_mbox_obj(self):<br>
> self.get_mbox()<br>
> return self._mbox_obj<br>
> <br>
> def get_mbox(self):<br>
> - if hasattr(self, "mbox"):<br>
> - return self.mbox<br>
> - self.mbox = load_blob(self.message_id)<br>
> - self._mbox_obj = MboxMessage(self.mbox)<br>
> - return self.mbox<br>
> -<br>
> + if hasattr(self, "mbox_blob"):<br>
> + return self.mbox_blob<br>
> + self.mbox_blob = load_blob(self.message_id)<br>
> + self._mbox_obj = MboxMessage(self.mbox_blob)<br>
> + return self.mbox_blob<br>
> + <br>
> + mbox = property(get_mbox)<br>
> + @mbox.setter<br>
> + def mbox(self,value):<br>
> + self.mbox_blob = value<br>
> + <br>
> def get_num(self):<br>
> assert self.is_patch or self.is_series_head<br>
> cur, total = 1, 1<br>
> diff --git a/api/rest.py b/api/rest.py<br>
> index fc10b46..7c38d39 100644<br>
> --- a/api/rest.py<br>
> +++ b/api/rest.py<br>
> @@ -140,9 +140,13 @@ class BaseMessageSerializer(serializers.ModelSerializer):<br>
> fields = ('resource_uri', 'message_id', 'subject', 'date', 'sender', 'recipients')<br>
> <br>
> resource_uri = HyperlinkedMessageField(view_name='messages-detail')<br>
> -<br>
> recipients = AddressSerializer(many=True)<br>
> - sender = AddressSerializer()<br>
> + sender = AddressSerializer() <br>
<br>
You're adding whitespace at the end of the line here.<br>
<br>
> + <br>
> + def create(self, validated_data):<br>
> + validated_data['recipients'] = self.fields['recipients'].create(validated_data['recipients'])<br>
> + validated_data['sender'] = self.fields['sender'].create(validated_data['sender'])<br>
> + return Message.objects.create(project=self.context['project'], **validated_data)<br>
> <br>
> # a message_id is *not* unique, so we can only list<br>
> class BaseMessageViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):<br>
> @@ -156,7 +160,9 @@ class BaseMessageViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):<br>
> class ProjectMessagesViewSetMixin(mixins.RetrieveModelMixin):<br>
> def get_queryset(self):<br>
> return self.queryset.filter(project=self.kwargs['projects_pk'])<br>
> -<br>
> + def get_serializer_context(self):<br>
> + return {'project': Project.objects.get(id=self.kwargs['projects_pk']), 'request': self.request}<br>
<br>
Good! Out of curiosity what do you actually need 'request' for?<br>
<br></blockquote><div>Request is used by dispatch_module_hook is BaseMessageSerializer <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
> # Series<br>
> <br>
> class ReplySerializer(BaseMessageSerializer):<br>
> @@ -287,10 +293,7 @@ class MessageSerializer(BaseMessageSerializer):<br>
> class Meta:<br>
> model = Message<br>
> fields = BaseMessageSerializer.Meta.fields + ('mbox', )<br>
> -<br>
> - def get_mbox(self, obj):<br>
> - return obj.get_mbox()<br>
> - mbox = SerializerMethodField()<br>
> + mbox = JSONField()<br>
<br>
Can this be a CharField() instead?<br></blockquote><div>Okay. </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
> <br>
> def get_fields(self):<br>
> fields = super(MessageSerializer, self).get_fields()<br>
> @@ -312,9 +315,8 @@ class StaticTextRenderer(renderers.BaseRenderer):<br>
> return data<br>
> <br>
> class MessagesViewSet(ProjectMessagesViewSetMixin,<br>
> - BaseMessageViewSet):<br>
> + BaseMessageViewSet, mixins.CreateModelMixin):<br>
> serializer_class = MessageSerializer<br>
> -<br>
> @detail_route(renderer_classes=[StaticTextRenderer])<br>
> def mbox(self, request, *args, **kwargs):<br>
> message = self.get_object()<br>
> <br>
<br>
</blockquote></div></div>