Repository: genialis/resolwe

Issue:
Data.create returns bad message when missing ADD permission on collection
If a user tries to run a process inside a collection, but doesn't have `ADD` permission, the api returns `{"detail":"Not found."}`


Discussion:

Resolving patch:
diff --git a/resolwe/flow/views/data.py b/resolwe/flow/views/data.py
--- a/resolwe/flow/views/data.py
+++ b/resolwe/flow/views/data.py
@@ -51,10 +51,14 @@ def create(self, request, *args, **kwargs):
                                 status=status.HTTP_400_BAD_REQUEST)
 
             if not request.user.has_perm('add_collection', obj=collection):
-                if request.user.is_authenticated():
-                    raise exceptions.PermissionDenied
+                if request.user.has_perm('view_collection', obj=collection):
+                    raise exceptions.PermissionDenied(
+                        "You don't have `ADD` permission on collection (id: {}).".format(collection_id)
+                    )
                 else:
-                    raise exceptions.NotFound
+                    raise exceptions.NotFound(
+                        "Collection not found (id: {}).".format(collection_id)
+                    )
 
         # translate processe's slug to id
         process_slug = request.data.get('process', None)
diff --git a/resolwe/flow/views/mixins.py b/resolwe/flow/views/mixins.py
--- a/resolwe/flow/views/mixins.py
+++ b/resolwe/flow/views/mixins.py
@@ -4,6 +4,7 @@
 from django.db import IntegrityError, transaction
 
 from guardian.shortcuts import assign_perm
+from guardian.utils import get_anonymous_user
 from rest_framework import mixins, status
 from rest_framework.decorators import list_route
 from rest_framework.response import Response
@@ -38,7 +39,11 @@ def create(self, request, *args, **kwargs):
                         'Invalid descriptor_schema slug "{}" - object does not exist.'.format(ds_slug)]},
                     status=status.HTTP_400_BAD_REQUEST)
 
-        request.data['contributor'] = request.user.pk
+        if request.user.is_anonymous():
+            request.data['contributor'] = get_anonymous_user().pk
+        else:
+            request.data['contributor'] = request.user.pk
+
         try:
             return super(ResolweCreateModelMixin, self).create(request, *args, **kwargs)
 


Test patch:
diff --git a/resolwe/flow/tests/test_api.py b/resolwe/flow/tests/test_api.py
--- a/resolwe/flow/tests/test_api.py
+++ b/resolwe/flow/tests/test_api.py
@@ -3,10 +3,12 @@
 
 import mock
 
+from django.contrib.auth.models import AnonymousUser
 from django.core.urlresolvers import reverse
 from django.db import DEFAULT_DB_ALIAS, connections
 from django.test.utils import CaptureQueriesContext
 
+from guardian.conf.settings import ANONYMOUS_USER_NAME
 from guardian.shortcuts import assign_perm, remove_perm
 from rest_framework import exceptions, status
 from rest_framework.test import APIRequestFactory, force_authenticate
@@ -92,6 +94,19 @@ def test_use_latest_with_perm(self):
         self.assertEqual(data.process, self.proc)
         self.assertEqual(data.descriptor_schema, self.descriptor_schema)
 
+    def test_public_create(self):
+        assign_perm('view_process', AnonymousUser(), self.proc)
+
+        data = {'process': 'test-process'}
+        request = factory.post('/', data, format='json')
+        resp = self.data_viewset(request)
+        self.assertEqual(resp.status_code, status.HTTP_201_CREATED)
+        self.assertEqual(Data.objects.count(), 1)
+
+        data = Data.objects.latest()
+        self.assertEqual(data.contributor.username, ANONYMOUS_USER_NAME)
+        self.assertEqual(data.process.slug, 'test-process')
+
 
 class TestCollectionViewSetCase(TestCase):
     def setUp(self):
diff --git a/resolwe/permissions/tests/test_data.py b/resolwe/permissions/tests/test_data.py
--- a/resolwe/permissions/tests/test_data.py
+++ b/resolwe/permissions/tests/test_data.py
@@ -109,7 +109,8 @@ def test_post_no_perms(self):
     def test_post_public_user(self):
         collection_n = Data.objects.count()
         resp = self._post(self.data)
-        self.assertEqual(resp.status_code, status.HTTP_404_NOT_FOUND)
+        # User has no permission to add Data object to the collection.
+        self.assertEqual(resp.status_code, status.HTTP_403_FORBIDDEN)
         self.assertEqual(Data.objects.count(), collection_n)
 
     def test_post_protected_fields(self):