diff --git a/onadata/apps/api/tests/viewsets/test_attachment_viewset.py b/onadata/apps/api/tests/viewsets/test_attachment_viewset.py index 40a0f18097..0ff13097c8 100644 --- a/onadata/apps/api/tests/viewsets/test_attachment_viewset.py +++ b/onadata/apps/api/tests/viewsets/test_attachment_viewset.py @@ -10,6 +10,9 @@ from onadata.apps.logger.import_tools import django_file from onadata.apps.logger.models.attachment import Attachment from onadata.apps.logger.models.instance import get_attachment_url +from onadata.apps.main.models.meta_data import MetaData +from onadata.libs.permissions import EditorRole +from onadata.libs.models.share_xform import ShareXForm def attachment_url(attachment, suffix=None): @@ -382,3 +385,34 @@ def test_total_count(self): '/count', data={"xform": xform_id}, **self.extra) response = self.count_view(request) self.assertEqual(response.data['count'], 1) + + def test_returned_attachments_is_based_on_form_permissions(self): + # Create a form and make submissions with attachments + self._submit_transport_instance_w_attachment() + + formid = self.xform.pk + request = self.factory.get( + '/', data={"xform": formid}, **self.extra) + response = self.list_view(request) + self.assertEqual(response.status_code, 200) + self.assertEqual(len(response.data), 1) + + user_dave = self._create_user_profile({"username": "dave"}).user + # Enable meta perms + data_value = "editor-minor|dataentry-minor" + MetaData.xform_meta_permission(self.xform, data_value=data_value) + + ShareXForm(self.xform, user_dave.username, EditorRole.name) + auth_extra = { + 'HTTP_AUTHORIZATION': f'Token {user_dave.auth_token.key}' + } + + # Dave user should not be able to view attachments for + # submissions which they did not submit + request = self.factory.get('/', data={"xform": formid}, **auth_extra) + response = self.list_view(request) + self.assertEqual(response.status_code, 200) + # Ensure no submissions are returned for the User + # daves' request as they have not submitted any data + # and meta permissions have been applied to the form + self.assertEqual(len(response.data), 0) diff --git a/onadata/libs/filters.py b/onadata/libs/filters.py index f5acf444ee..9c14884361 100644 --- a/onadata/libs/filters.py +++ b/onadata/libs/filters.py @@ -16,6 +16,8 @@ from onadata.apps.viewer.models import Export from onadata.libs.utils.numeric import int_or_parse_error from onadata.libs.utils.common_tags import MEDIA_FILE_TYPES +from onadata.libs.permissions import \ + exclude_items_from_queryset_using_xform_meta_perms class AnonDjangoObjectPermissionFilter(ObjectPermissionsFilter): @@ -412,6 +414,15 @@ def filter_queryset(self, request, queryset, view): queryset = self._xform_filter_queryset(request, queryset, view, 'instance__xform') + # Ensure queryset is filtered by XForm meta permissions + xform_ids = set( + queryset.values_list("instance__xform", flat=True)) + for xform_id in xform_ids: + xform = XForm.objects.get(id=xform_id) + user = request.user + queryset = exclude_items_from_queryset_using_xform_meta_perms( + xform, user, queryset) + instance_id = request.query_params.get('instance') if instance_id: int_or_parse_error(instance_id, diff --git a/onadata/libs/permissions.py b/onadata/libs/permissions.py index 05b61a9596..af8bf3c30f 100644 --- a/onadata/libs/permissions.py +++ b/onadata/libs/permissions.py @@ -7,11 +7,13 @@ import six from django.db.models.base import ModelBase +from django.db.models import Q from guardian.shortcuts import (assign_perm, get_perms, get_users_with_perms, remove_perm) from onadata.apps.api.models import OrganizationProfile -from onadata.apps.logger.models import MergedXForm, Project, XForm +from onadata.apps.logger.models import MergedXForm, Project, XForm,\ + Attachment from onadata.apps.logger.models.project import (ProjectGroupObjectPermission, ProjectUserObjectPermission) from onadata.apps.logger.models.xform import (XFormGroupObjectPermission, @@ -496,6 +498,23 @@ def _check_meta_perms_enabled(xform): return xform.metadata_set.filter(data_type=XFORM_META_PERMS).count() > 0 +def exclude_items_from_queryset_using_xform_meta_perms( + xform, user, queryset): + """ + Exclude instances from the queryset if meta-perms have been enabled + """ + if user.has_perm(CAN_VIEW_XFORM_ALL, xform) or xform.shared_data \ + or not _check_meta_perms_enabled(xform): + return queryset + elif user.has_perm(CAN_VIEW_XFORM_DATA, xform): + if queryset.model is Attachment: + return queryset.exclude( + ~Q(instance__user=user), instance__xform=xform) + else: + return queryset.exclude( + ~Q(user=user), xform=xform) + + def filter_queryset_xform_meta_perms(xform, user, instance_queryset): """ Check for the specific perms if meta-perms have been enabled