示例#1
0
    def get_queryset(self):
        queryset = Asset.objects.filter(asset_type=ASSET_TYPE_SURVEY)
        if self.action == 'retrieve':
            # `get_object()` will do the checking; no need to manipulate the
            # queryset further
            return queryset.defer('content')

        # `ReportsListSerializer` needs only the UID; don't bother retrieving
        # anything else from the database
        queryset = queryset.only('uid')

        # Reduce the number of asset versions we have to consider by filtering
        # for accessible assets first
        owned_and_explicitly_shared = get_objects_for_user(
            self.request.user,
            self.required_permissions,
            queryset,
            all_perms_required=False,
        )
        subscribed_and_public = get_objects_for_user(
            get_anonymous_user(),
            self.required_permissions,
            queryset.filter(
                parent__userassetsubscription__user=self.request.user),
            all_perms_required=False,
        )

        # Find which of these are deployed, using a custom manager method
        deployed_assets = (owned_and_explicitly_shared | subscribed_and_public
                           ) & Asset.objects.deployed().distinct()

        return deployed_assets
示例#2
0
    def test_viewers_see_only_self_anon_and_owner_assignments(self):

        self.client.login(username='******', password='******')
        permission_list_response = self.client.get(
            self.get_asset_perm_assignment_list_url(self.asset), format='json')
        self.assertEqual(permission_list_response.status_code,
                         status.HTTP_200_OK)
        results = permission_list_response.data

        # `anotheruser` must see only permissions assigned to themselves, the
        # owner (`self.admin`) and the anonymous user. Permissions assigned to
        # `someuser` must not appear
        assignable_perms = self.asset.get_assignable_permissions()
        expected_perms = []
        for user in [self.admin, self.anotheruser, get_anonymous_user()]:
            user_perms = self.asset.get_perms(user)
            expected_perms.extend(
                (user.username, perm)
                for perm in set(user_perms).intersection(assignable_perms))
        expected_perms = sorted(expected_perms,
                                key=lambda element: (element[0], element[1]))

        obj_perms = []
        for assignment in results:
            object_permission = self.url_to_obj(assignment.get('url'))
            obj_perms.append((
                object_permission.user.username,
                object_permission.permission.codename,
            ))
        obj_perms = sorted(obj_perms,
                           key=lambda element: (element[0], element[1]))

        self.assertEqual(expected_perms, obj_perms)
示例#3
0
    def _get_subscribed(cls, user):
        # Of the public objects, determine to which the user has subscribed
        if is_user_anonymous(user):
            user = get_anonymous_user()

        return UserAssetSubscription.objects.filter(
            asset__in=cls._get_publics(), user=user).values('asset')
示例#4
0
    def filter_queryset(self, request, queryset, view):
        # TODO: omit objects for which the user has only a deny permission
        user = request.user
        if isinstance(request.user, AnonymousUser):
            user = get_anonymous_user()

        if user.is_superuser:
            # Superuser sees all
            return queryset
        if user.pk == settings.ANONYMOUS_USER_ID:
            # Hide permissions from anonymous users
            return queryset.none()
        """
        A regular user sees their own permissions and the owner's permissions
        for objects to which they have access. For example, if Alana and John
        have view access to an object owned by Richard, John should see all of
        his own permissions and Richard's permissions, but not any of Alana's
        permissions.
        """
        result = ObjectPermission.objects.filter(
            Q(asset__owner=user)  # owner sees everything
            | Q(user=user)  # everyone with access sees their own
            | Q(
                # everyone with access sees the owner's
                asset__permissions__user=user,
                user=F('asset__owner'))).distinct()
        return result
示例#5
0
    def _get_queryset_for_discoverable_child_assets(
            self, request: Request, queryset: QuerySet) -> QuerySet:
        """
        Returns a queryset containing the children of publically discoverable
        assets based on the discoverability of the child's parent. The parent
        uid is passed in the request query string.
        """

        self._return_queryset = False

        parameters = self.__get_parsed_parameters(request)
        try:
            parent_uids = parameters[self.PARENT_UID_PARAMETER]
        except KeyError:
            return queryset

        # `self.__get_parsed_parameters()` returns a list for each parameters
        # but we should only search only with one parent uid
        parent_obj = queryset.get(uid=parent_uids[0])

        if not isinstance(parent_obj, Asset):
            return queryset

        if parent_obj.has_perm(get_anonymous_user(), PERM_DISCOVER_ASSET):
            self._return_queryset = True
            return queryset.filter(pk__in=self._get_publics(),
                                   parent=parent_obj)

        return queryset
示例#6
0
    def test_anonymous_get_only_owner_and_anonymous_assignments(self):

        self.client.logout()
        permission_list_response = self.client.get(
            self.get_asset_perm_assignment_list_url(self.asset), format='json')
        self.assertEqual(permission_list_response.status_code,
                         status.HTTP_200_OK)
        admin = self.admin
        admin_perms = self.asset.get_perms(admin)
        anon = get_anonymous_user()
        anon_perms = self.asset.get_perms(anon)
        assignable_perms = self.asset.get_assignable_permissions()
        results = permission_list_response.data

        # Get admin permissions.
        expected_perms = []
        for user, perms in [(anon, anon_perms), (admin, admin_perms)]:
            for perm in perms:
                if perm in assignable_perms:
                    expected_perms.append((user.username, perm))

        expected_perms = sorted(expected_perms,
                                key=lambda element: (element[0], element[1]))
        obj_perms = []
        for assignment in results:
            object_permission = self.url_to_obj(assignment.get('url'))
            obj_perms.append((object_permission.user.username,
                              object_permission.permission.codename))

        obj_perms = sorted(obj_perms,
                           key=lambda element: (element[0], element[1]))
        self.assertEqual(expected_perms, obj_perms)
示例#7
0
    def test_different_sort_between_python_and_db(self):

        # Ensure that `AnonymousUser` is created to include it in the list below
        get_anonymous_user()

        User.objects.bulk_create([
            User(first_name='A', last_name='User', username='******'),
            User(first_name='Alexander',
                 last_name='Mtembenuzeni',
                 username='******'),
            User(first_name='Another',
                 last_name='User',
                 username='******'),
        ])

        users = list(
            User.objects.filter(username__istartswith='a').values_list(
                'username', flat=True).order_by('username'))

        # The database (PostgreSQL, as of Jun, 14, 2022) seems to be case
        # insensitive and treats `_` after any letters.
        # Python is case sensitive and treats `_` before any letters.
        expected_database = [
            'alex_Mtemb',
            'AnonymousUser',
            'anotheruser',
            'a_user',
        ]

        expected_python = [
            'AnonymousUser',
            'a_user',
            'alex_Mtemb',
            'anotheruser',
        ]

        self.assertEqual(users, expected_database)
        self.assertEqual(sorted(users), expected_python)
        # Obviously if the first two assertions are True, the one below should
        # be false. No matter what, let's be paranoid and test it anyway.
        self.assertNotEqual(users, sorted(users))
示例#8
0
    def setUp(self):
        super().setUp()
        self.anon = get_anonymous_user()
        self.super = User.objects.get(username='******')
        self.super_password = '******'
        self.someuser = User.objects.get(username='******')
        self.someuser_password = '******'
        self.anotheruser = User.objects.get(username='******')
        self.anotheruser_password = '******'

        self.collection = Asset.objects.create(
            asset_type=ASSET_TYPE_COLLECTION, owner=self.someuser)
        self.asset = Asset.objects.create(owner=self.someuser)
示例#9
0
    def test_synchronous_csv_export_anonymous_with_permission(self):
        self.asset.assign_perm(get_anonymous_user(), PERM_VIEW_SUBMISSIONS)

        es = self._create_export_settings()

        synchronous_exports_url = reverse(
            self._get_endpoint('asset-export-settings-synchronous-data'),
            kwargs={
                'parent_lookup_asset': self.asset.uid,
                'uid': es.uid,
                'format': 'csv',
            },
        )
        response = self.client.get(synchronous_exports_url, follow=True)
        assert response.status_code == status.HTTP_200_OK
示例#10
0
    def setUp(self):
        KpiTestCase.setUp(self)

        self.anon = get_anonymous_user()
        self.admin = User.objects.get(username='******')
        self.admin_password = '******'
        self.someuser = User.objects.get(username='******')
        self.someuser_password = '******'

        self.login(self.admin.username, self.admin_password)
        self.admins_public_asset = self.create_asset('admins_public_asset')
        self.add_perm(self.admins_public_asset, self.anon, 'view')

        self.login(self.someuser.username, self.someuser_password)
        self.someusers_public_asset = self.create_asset(
            'someusers_public_asset')
        self.add_perm(self.someusers_public_asset, self.anon, 'view')
示例#11
0
    def setUp(self):
        self.anon = get_anonymous_user()
        self.someuser = User.objects.get(username='******')
        self.someuser_password = '******'

        # This was written when we allowed anons to create assets, but I'll
        # leave it here just to make sure it has no effect
        permission = Permission.objects.get(codename='add_asset')
        self.anon.user_permissions.add(permission)

        # Log in and create an asset that anon can access
        self.client.login(username=self.someuser.username,
                          password=self.someuser_password)
        self.anon_accessible = self.create_asset('Anonymous can access this!')
        self.add_perm(self.anon_accessible, self.anon, 'view_')
        # Log out and become anonymous again
        self.client.logout()
        response = self.client.get(reverse('currentuser-detail'))
        self.assertFalse('username' in response.data)
示例#12
0
    def test_export_task_list_anon_public_asset(self):
        # make submissions public
        self.asset.assign_perm(get_anonymous_user(), PERM_VIEW_SUBMISSIONS)
        for _type in ['csv', 'xls', 'spss_labels']:
            self._create_export_task(_type=_type)

        self.client.logout()
        list_url = reverse(
            self._get_endpoint('asset-export-list'),
            kwargs={
                'format': 'json',
                'parent_lookup_asset': self.asset.uid
            },
        )
        response = self.client.get(list_url)
        assert response.status_code == status.HTTP_200_OK

        data = response.json()
        # should not list any results as exports were created by another user
        assert not data['results']
示例#13
0
    def setUp(self):
        super().setUp()
        self.anon = get_anonymous_user()
        self.super = User.objects.get(username='******')
        self.super_password = '******'
        self.someuser = User.objects.get(username='******')
        self.someuser_password = '******'
        self.anotheruser = User.objects.get(username='******')
        self.anotheruser_password = '******'

        def create_object_with_specific_pk(model, pk, **kwargs):
            obj = model()
            obj.pk = pk
            for k, v in kwargs.items():
                setattr(obj, k, v)
            obj.save()
            return obj

        self.collection = Asset.objects.create(
            asset_type=ASSET_TYPE_COLLECTION, owner=self.someuser
        )
        self.asset = Asset.objects.create(owner=self.someuser)
示例#14
0
    def test_create_export_anon(self):
        anon = get_anonymous_user()
        self.asset.assign_perm(anon, PERM_VIEW_SUBMISSIONS)
        self._create_export_task(_type='xls', user=self.user)

        self.client.logout()
        self._create_export_task(_type='xls', user=anon)
        list_url = reverse(
            self._get_endpoint('asset-export-list'),
            kwargs={
                'format': 'json',
                'parent_lookup_asset': self.asset.uid
            },
        )
        response = self.client.get(list_url)
        assert response.status_code == status.HTTP_200_OK

        data = response.json()
        # two total exports on asset, but only one by anon
        assert len(data['results']) == 1

        download_url = data['results'][0]['result']
        download_response = self.client.get(download_url)
        assert download_response.status_code == status.HTTP_200_OK
示例#15
0
 def _get_discoverable(self, queryset):
     # We were asked not to consider subscriptions; return all
     # discoverable objects
     return get_objects_for_user(get_anonymous_user(), PERM_DISCOVER_ASSET,
                                 queryset)
示例#16
0
    def setUp(self):
        super().setUp()

        self.asset.assign_perm(self.someuser, PERM_CHANGE_ASSET)
        self.asset.assign_perm(self.anotheruser, PERM_VIEW_ASSET)
        self.asset.assign_perm(get_anonymous_user(), PERM_VIEW_ASSET)
示例#17
0
 def _get_publics():
     view_asset_perm_id = get_perm_ids_from_code_names(PERM_VIEW_ASSET)
     return ObjectPermission.objects.filter(
         deny=False,
         user=get_anonymous_user(),
         permission_id=view_asset_perm_id).values('asset')
示例#18
0
from kpi.deployment_backends.kobocat_backend import KobocatDeploymentBackend
from kpi.models import Asset, ObjectPermission
from kpi.utils.object_permission import get_anonymous_user
from kpi.utils.models import _set_auto_field_update

TIMESTAMP_DIFFERENCE_TOLERANCE = datetime.timedelta(seconds=30)

# Swap keys and values so that keys are KC's codenames and values are KPI's
PERMISSIONS_MAP = {kc: kpi for kpi, kc in Asset.KC_PERMISSIONS_MAP.items()}

# Optimization
ASSET_CT = ContentType.objects.get_for_model(Asset)
FROM_KC_ONLY_PERMISSION = Permission.objects.get(
    content_type=ASSET_CT, codename=PERM_FROM_KC_ONLY)
XFORM_CT = ShadowModel.get_content_type_for_model(KobocatXForm)
ANONYMOUS_USER = get_anonymous_user()
# Replace codenames with Permission PKs, remembering the codenames
permission_map_copy = dict(PERMISSIONS_MAP)

KPI_PKS_TO_CODENAMES = {}
for kc_codename, kpi_codename in permission_map_copy.items():
    kc_perm_pk = KobocatPermission.objects.get(
        content_type=XFORM_CT, codename=kc_codename).pk
    kpi_perm_pk = Permission.objects.get(
        content_type=ASSET_CT, codename=kpi_codename).pk

    del PERMISSIONS_MAP[kc_codename]

    PERMISSIONS_MAP[kc_perm_pk] = kpi_perm_pk
    KPI_PKS_TO_CODENAMES[kpi_perm_pk] = kpi_codename
示例#19
0
    def test_no_assignments_saved_on_error(self):

        # Call `get_anonymous_user()` to create AnonymousUser if it does not exist
        get_anonymous_user()

        # Ensure someuser and anotheruser do not have 'view_submissions' on `self.asset`
        self.assertFalse(
            self.asset.has_perm(self.someuser, PERM_VIEW_SUBMISSIONS))
        self.assertFalse(
            self.asset.has_perm(self.anotheruser, PERM_VIEW_SUBMISSIONS))

        # Allow someuser and anotheruser to view submissions
        good_assignments = [{
            'user': '******',
            'permission': PERM_VIEW_SUBMISSIONS,
        }, {
            'user': '******',
            'permission': PERM_VIEW_SUBMISSIONS,
        }]

        assignments = self.translate_usernames_and_codenames_to_urls(
            good_assignments)
        bulk_endpoint = reverse(
            self._get_endpoint('asset-permission-assignment-bulk-assignments'),
            kwargs={'parent_lookup_asset': self.asset.uid})
        response = self.client.post(bulk_endpoint, assignments, format='json')

        # Everything worked as expected, someuser and anotheruser got 'view_submissions'
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertTrue(
            self.asset.has_perm(self.someuser, PERM_VIEW_SUBMISSIONS))
        self.assertTrue(
            self.asset.has_perm(self.anotheruser, PERM_VIEW_SUBMISSIONS))

        # but do not have respectively 'delete_submissions' and 'change_submissions'
        self.assertFalse(
            self.asset.has_perm(self.someuser, PERM_DELETE_SUBMISSIONS))
        self.assertFalse(
            self.asset.has_perm(self.anotheruser, PERM_CHANGE_SUBMISSIONS))

        bad_assignments = [
            {
                'user': '******',
                'permission': PERM_ADD_SUBMISSIONS,  # should return a 400
            },
            {
                'user': '******',
                'permission': PERM_DELETE_SUBMISSIONS,
            },
            {
                'user': '******',
                'permission': PERM_CHANGE_SUBMISSIONS,
            }
        ]
        assignments = self.translate_usernames_and_codenames_to_urls(
            bad_assignments)

        bulk_endpoint = reverse(
            self._get_endpoint('asset-permission-assignment-bulk-assignments'),
            kwargs={'parent_lookup_asset': self.asset.uid})
        response = self.client.post(bulk_endpoint, assignments, format='json')
        # Could not assign 'add_submissions' to anonymous user.
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

        # Ensure that someuser and anotheruser did not get any other permissions
        # than the one they already had, i.e.: 'view_submissions'.
        self.assertFalse(
            self.asset.has_perm(self.someuser, PERM_DELETE_SUBMISSIONS))
        self.assertFalse(
            self.asset.has_perm(self.anotheruser, PERM_CHANGE_SUBMISSIONS))
示例#20
0
 def __init__(self, *args, **kwargs):
     super().__init__(*args, **kwargs)
     self.fields['asset'].queryset = get_objects_for_user(
         get_anonymous_user(), [PERM_VIEW_ASSET, PERM_DISCOVER_ASSET],
         Asset)