33from django .db .models import Q
44from django .http import Http404
55
6+ import commonware .log
67from rest_framework .exceptions import PermissionDenied
78from rest_framework .mixins import (CreateModelMixin , DestroyModelMixin ,
89 ListModelMixin , RetrieveModelMixin )
910from rest_framework .permissions import BasePermission
1011from rest_framework .relations import HyperlinkedRelatedField , RelatedField
1112from rest_framework .serializers import ModelSerializer
12- from rest_framework .viewsets import GenericViewSet
1313
1414from access import acl
1515from comm .models import (CommunicationNote , CommunicationThread ,
16- CommunicationThreadCC )
16+ CommunicationThreadCC , CommunicationThreadToken )
1717from mkt .api .authentication import (RestOAuthAuthentication ,
1818 RestSharedSecretAuthentication )
19+ from mkt .api .base import CORSViewSet
1920from mkt .webpay .forms import PrepareForm
2021
22+ log = commonware .log .getLogger ('mkt.comm' )
23+
2124
2225class NoteSerializer (ModelSerializer ):
23- thread = HyperlinkedRelatedField (read_only = True ,
24- view_name = 'comm-thread-detail' )
26+ thread = HyperlinkedRelatedField (view_name = 'comm-thread-detail' )
2527 body = RelatedField ('body' )
2628
2729 class Meta :
@@ -77,7 +79,6 @@ def has_object_permission(self, request, view, obj):
7779 Moreover, other object permissions are also checked agaisnt the ACLs
7880 of the user.
7981 """
80-
8182 if not request .user .is_authenticated () or obj .read_permission_public :
8283 return obj .read_permission_public
8384
@@ -86,6 +87,7 @@ def has_object_permission(self, request, view, obj):
8687 thread = obj )
8788 user_cc = CommunicationThreadCC .objects .filter (user = profile ,
8889 thread = obj )
90+
8991 if user_post .exists () or user_cc .exists ():
9092 return True
9193
@@ -114,18 +116,41 @@ def has_object_permission(self, request, view, obj):
114116
115117
116118class NotePermission (ThreadPermission ):
119+
120+ def has_permission (self , request , view ):
121+ if view .action == 'create' :
122+ if not request .user .is_authenticated ():
123+ return False
124+
125+ serializer = view .get_serializer (data = request .DATA )
126+ if not serializer .is_valid ():
127+ return False
128+
129+ obj = serializer .object
130+ # Check if author and user who created this request mismatch.
131+ if obj .author .id != request .amo_user .id :
132+ return False
133+
134+ # Determine permission to add the note based on the thread
135+ # permission.
136+ return ThreadPermission .has_object_permission (self ,
137+ request , view , obj .thread )
138+
139+ return True
140+
117141 def has_object_permission (self , request , view , obj ):
118- return super ( ThreadPermission , self ) .has_object_permission (request ,
119- view , obj .thread )
142+ return ThreadPermission .has_object_permission (self , request , view ,
143+ obj .thread )
120144
121145
122146class ThreadViewSet (ListModelMixin , RetrieveModelMixin , DestroyModelMixin ,
123- CreateModelMixin , GenericViewSet ):
147+ CreateModelMixin , CORSViewSet ):
124148 model = CommunicationThread
125149 serializer_class = ThreadSerializer
126150 authentication_classes = (RestOAuthAuthentication ,
127151 RestSharedSecretAuthentication )
128152 permission_classes = (ThreadPermission ,)
153+ cors_allowed_methods = ['get' , 'post' ]
129154
130155 def list (self , request ):
131156 profile = request .amo_user
@@ -145,20 +170,31 @@ def list(self, request):
145170 addon = form .cleaned_data ['app' ])
146171 else :
147172 # We list all the threads which uses an add-on authored by the
148- # user.
173+ # user and with read permissions for add-on devs .
149174 notes , cc = list (notes ), list (cc )
150175 addons = list (profile .addons .values_list ('pk' , flat = True ))
176+ q_dev = Q (addon__in = addons , read_permission_developer = True )
151177 queryset = CommunicationThread .objects .filter (
152- Q (pk__in = notes + cc ) | Q ( addon__in = addons ) )
178+ Q (pk__in = notes + cc ) | q_dev )
153179
154180 self .queryset = queryset
155181 return ListModelMixin .list (self , request )
156182
157183
158184class NoteViewSet (CreateModelMixin , RetrieveModelMixin , DestroyModelMixin ,
159- GenericViewSet ):
185+ CORSViewSet ):
160186 model = CommunicationNote
161187 serializer_class = NoteSerializer
162188 authentication_classes = (RestOAuthAuthentication ,
163189 RestSharedSecretAuthentication ,)
164190 permission_classes = (NotePermission ,)
191+ cors_allowed_methods = ['get' , 'post' , 'delete' ]
192+
193+ def create (self , request ):
194+ res = CreateModelMixin .create (self , request )
195+ if res .status_code == 201 :
196+ tok = CommunicationThreadToken .objects .create (
197+ thread = self .object .thread , user = self .object .author )
198+ log .info ('Reply token with UUID %s created.' % (tok .uuid ))
199+
200+ return res
0 commit comments