<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>