Пример #1
0
def _filter_datasets_by_permissions(datasets, user):
    """
    Filter out datasets that the user is not allowed to even know about
    @param datasets: django queryset
    @param user: request.user
    @return: queryset with filter applied
    """
    visibility_filter = Q(published=True)

    if datasets.model is ReferenceDataset:
        if user.has_perm(
                dataset_type_to_manage_unpublished_permission_codename(
                    DataSetType.REFERENCE)):
            visibility_filter |= Q(published=False)

    if datasets.model is DataSet:
        if user.has_perm(
                dataset_type_to_manage_unpublished_permission_codename(
                    DataSetType.MASTER)):
            visibility_filter |= Q(published=False, type=DataSetType.MASTER)

        if user.has_perm(
                dataset_type_to_manage_unpublished_permission_codename(
                    DataSetType.DATACUT)):
            visibility_filter |= Q(published=False, type=DataSetType.DATACUT)

    if datasets.model is VisualisationCatalogueItem:
        if user.has_perm(
                dataset_type_to_manage_unpublished_permission_codename(
                    DataSetType.VISUALISATION)):
            visibility_filter |= Q(published=False)

    datasets = datasets.filter(visibility_filter)
    return datasets
Пример #2
0
def test_dataset_type_to_manage_unpublished_permission_codename():
    assert (dataset_type_to_manage_unpublished_permission_codename(0) ==
            'datasets.manage_unpublished_reference_datasets')
    assert (dataset_type_to_manage_unpublished_permission_codename(
        DataSet.TYPE_DATA_CUT) ==
            'datasets.manage_unpublished_datacut_datasets')
    assert (dataset_type_to_manage_unpublished_permission_codename(
        DataSet.TYPE_MASTER_DATASET) ==
            'datasets.manage_unpublished_master_datasets')
Пример #3
0
def filter_datasets(
    datasets: Union[ReferenceDataset, DataSet],
    query,
    source,
    use=None,
    user=None,
    form=None,
):
    search = SearchVector('name', 'short_description', config='english')
    search_query = SearchQuery(query, config='english')

    dataset_filter = Q(published=True)

    if user:
        if datasets.model is ReferenceDataset:
            reference_type = DataSetType.REFERENCE.value
            reference_perm = dataset_type_to_manage_unpublished_permission_codename(
                reference_type)

            if user.has_perm(reference_perm):
                dataset_filter |= Q(published=False)

        if datasets.model is DataSet:
            master_type, datacut_type = (
                DataSetType.MASTER.value,
                DataSetType.DATACUT.value,
            )
            master_perm = dataset_type_to_manage_unpublished_permission_codename(
                master_type)
            datacut_perm = dataset_type_to_manage_unpublished_permission_codename(
                datacut_type)

            if user.has_perm(master_perm) and (not use
                                               or str(master_type) in use):
                dataset_filter |= Q(published=False, type=master_type)

            if user.has_perm(datacut_perm) and (not use
                                                or str(datacut_type) in use):
                dataset_filter |= Q(published=False, type=datacut_type)

    datasets = datasets.filter(dataset_filter).annotate(search=search,
                                                        search_rank=SearchRank(
                                                            search,
                                                            search_query))

    if query:
        datasets = datasets.filter(search=query)

    if source:
        datasets = datasets.filter(source_tags__in=source)

    if use:
        datasets = datasets.filter(type__in=use)

    return datasets
Пример #4
0
    def get_object(self, queryset=None):
        dataset_uuid = self.kwargs['dataset_uuid']
        dataset = None
        try:
            dataset = ReferenceDataset.objects.live().get(uuid=dataset_uuid)
        except ReferenceDataset.DoesNotExist:
            try:
                dataset = DataSet.objects.live().get(id=dataset_uuid)
            except DataSet.DoesNotExist:
                try:
                    dataset = VisualisationCatalogueItem.objects.live().get(
                        id=dataset_uuid)
                except VisualisationCatalogueItem.DoesNotExist:
                    pass

        if dataset:
            perm_codename = dataset_type_to_manage_unpublished_permission_codename(
                dataset.type)

            if not dataset.published and not self.request.user.has_perm(
                    perm_codename):
                dataset = None

        if not dataset:
            raise Http404('No dataset matches the given query.')

        return dataset
Пример #5
0
    def test_grants_manage_unpublished_visualisations_permission(self):
        user = factories.UserFactory.create(
            username='******',
            is_staff=False,
            is_superuser=False,
        )
        visualisation = factories.VisualisationCatalogueItemFactory.create(
            published=False, visualisation_template__gitlab_project_id=1)
        perm_codename = dataset_type_to_manage_unpublished_permission_codename(
            DataSetType.VISUALISATION.value)
        assert user.has_perm(perm_codename) is False

        with requests_mock.Mocker() as rmock:
            rmock.get(
                f'http://127.0.0.1:8007/api/v4/users?extern_uid={user.profile.sso_id}&provider=oauth2_generic',
                json=[{
                    "id": 1
                }],
            )
            rmock.get(
                'http://127.0.0.1:8007/api/v4/projects/1/members/all?user_ids=1',
                json=[{
                    "id": 1,
                    "access_level": 50
                }],
            )
            has_access = gitlab_has_developer_access(
                user, visualisation.visualisation_template.gitlab_project_id)

        # Permissions are cached on the instance so we need to re-fetch it entirely - refresh_from_db insufficient.
        # https://docs.djangoproject.com/en/3.0/topics/auth/default/#permission-caching
        user = get_object_or_404(get_user_model(), pk=user.id)
        assert has_access is True
        assert user.has_perm(perm_codename) is True
Пример #6
0
def filter_visualisations(query, access, source, user=None):
    search = SearchVector('name', 'short_description', config='english')
    search_query = SearchQuery(query, config='english')

    if user and user.has_perm(
            dataset_type_to_manage_unpublished_permission_codename(
                DataSetType.VISUALISATION.value)):
        published_filter = Q()
    else:
        published_filter = Q(published=True)

    visualisations = VisualisationCatalogueItem.objects.filter(
        published_filter).annotate(search=search,
                                   search_rank=SearchRank(
                                       search, search_query))

    if query:
        visualisations = visualisations.filter(search=query)

    if user and access:
        access_filter = (Q(user_access_type='REQUIRES_AUTHENTICATION')
                         &
                         (Q(visualisationuserpermission__user=user)
                          | Q(visualisationuserpermission__isnull=True))) | Q(
                              user_access_type='REQUIRES_AUTHORIZATION',
                              visualisationuserpermission__user=user,
                          )
        visualisations = visualisations.filter(access_filter)

    if source:
        visualisations = visualisations.filter(
            visualisation_template__datasetapplicationtemplatepermission__dataset__source_tags__in
            =source)

    return visualisations
Пример #7
0
def has_unpublished_dataset_access(user):
    access = user.is_superuser
    for dataset_type in DataSetType:
        access = access or user.has_perm(
            dataset_type_to_manage_unpublished_permission_codename(
                dataset_type.value))

    return access
Пример #8
0
def _ensure_user_has_manage_unpublish_perm(user):
    # Update the django permission controlling whether the user can preview unpublished visualisation catalogue pages.
    perm_codename = dataset_type_to_manage_unpublished_permission_codename(
        DataSetType.VISUALISATION.value
    )
    app_label, codename = perm_codename.split('.')
    perm = Permission.objects.get(content_type__app_label=app_label, codename=codename)

    if not user.has_perm(perm_codename):
        with transaction.atomic():
            user.user_permissions.add(perm)
            user.save()
            LogEntry.objects.log_action(
                user_id=user.pk,
                content_type_id=ContentType.objects.get_for_model(user).pk,
                object_id=user.pk,
                object_repr=force_str(user),
                action_flag=ADDITION,
                change_message="Added 'manage unpublished visualisations' permission",
            )
Пример #9
0
def get_datasets_data_for_user_matching_query(datasets: QuerySet,
                                              query,
                                              use=None,
                                              user=None,
                                              id_field='id'):
    """
    Filters the dataset queryset for:
        1) visibility (whether the user can know if the dataset exists)
        2) matches the search terms

    Annotates the dataset queryset with:
        1) `has_access`, if the user can use the dataset's data.
    """
    is_reference_query = datasets.model is ReferenceDataset

    # Filter out datasets that the user is not allowed to even know about.
    visibility_filter = Q(published=True)

    if user:
        if is_reference_query:
            reference_type = DataSetType.REFERENCE.value
            reference_perm = dataset_type_to_manage_unpublished_permission_codename(
                reference_type)

            if user.has_perm(reference_perm):
                visibility_filter |= Q(published=False)

        if datasets.model is DataSet:
            master_type, datacut_type = (
                DataSetType.MASTER.value,
                DataSetType.DATACUT.value,
            )
            master_perm = dataset_type_to_manage_unpublished_permission_codename(
                master_type)
            datacut_perm = dataset_type_to_manage_unpublished_permission_codename(
                datacut_type)

            if user.has_perm(master_perm):
                visibility_filter |= Q(published=False, type=master_type)

            if user.has_perm(datacut_perm):
                visibility_filter |= Q(published=False, type=datacut_type)

    datasets = datasets.filter(visibility_filter)

    # Filter out datasets that don't match the search terms
    search = (SearchVector('name', weight='A', config='english') +
              SearchVector('short_description', weight='B', config='english') +
              SearchVector(StringAgg('tags__name', delimiter='\n'),
                           weight='B',
                           config='english'))
    search_query = SearchQuery(query, config='english')

    datasets = datasets.annotate(search=search,
                                 search_rank=SearchRank(search, search_query))

    if query:
        datasets = datasets.filter(search=search_query)

    # Mark up whether the user can access the data in the dataset.
    access_filter = Q()

    if user and datasets.model is not ReferenceDataset:
        access_filter &= (Q(user_access_type='REQUIRES_AUTHENTICATION')
                          & (Q(datasetuserpermission__user=user)
                             | Q(datasetuserpermission__isnull=True))) | Q(
                                 user_access_type='REQUIRES_AUTHORIZATION',
                                 datasetuserpermission__user=user)

    datasets = datasets.annotate(_has_access=Case(
        When(access_filter, then=True),
        default=False,
        output_field=BooleanField(),
    ) if access_filter else Value(True, BooleanField()), )

    # Pull in the source tag IDs for the dataset
    datasets = datasets.annotate(source_tag_ids=ArrayAgg(
        'tags', filter=Q(tags__type=TagType.SOURCE.value), distinct=True))
    datasets = datasets.annotate(source_tag_names=ArrayAgg(
        'tags__name', filter=Q(
            tags__type=TagType.SOURCE.value), distinct=True))

    # Pull in the topic tag IDs for the dataset
    datasets = datasets.annotate(topic_tag_ids=ArrayAgg(
        'tags', filter=Q(tags__type=TagType.TOPIC.value), distinct=True))
    datasets = datasets.annotate(topic_tag_names=ArrayAgg(
        'tags__name', filter=Q(tags__type=TagType.TOPIC.value), distinct=True))

    # Define a `purpose` column denoting the dataset type.
    if is_reference_query:
        datasets = datasets.annotate(
            purpose=Value(DataSetType.REFERENCE.value, IntegerField()))
    else:
        datasets = datasets.annotate(purpose=F('type'))

    # We are joining on the user permissions table to determine `_has_access`` to the dataset, so we need to
    # group them and remove duplicates. We aggregate all the `_has_access` fields together and return true if any
    # of the records say that access is available.
    datasets = datasets.values(
        id_field,
        'name',
        'slug',
        'short_description',
        'search_rank',
        'source_tag_names',
        'source_tag_ids',
        'topic_tag_names',
        'topic_tag_ids',
        'purpose',
        'published',
        'published_at',
    ).annotate(has_access=BoolOr('_has_access'))

    return datasets.values(
        id_field,
        'name',
        'slug',
        'short_description',
        'search_rank',
        'source_tag_names',
        'source_tag_ids',
        'topic_tag_names',
        'topic_tag_ids',
        'purpose',
        'published',
        'published_at',
        'has_access',
    )
Пример #10
0
def get_visualisations_data_for_user_matching_query(visualisations: QuerySet,
                                                    query,
                                                    user=None):
    """
    Filters the visualisation queryset for:
        1) visibility (whether the user can know if the visualisation exists)
        2) matches the search terms

    Annotates the visualisation queryset with:
        1) `has_access`, if the user can use the visualisation.
    """
    # Filter out visualisations that the user is not allowed to even know about.
    if not (user and user.has_perm(
            dataset_type_to_manage_unpublished_permission_codename(
                DataSetType.VISUALISATION.value))):
        visualisations = visualisations.filter(published=True)

    # Filter out visualisations that don't match the search terms
    search = SearchVector('name', weight='A', config='english') + SearchVector(
        'short_description', weight='B', config='english')
    search_query = SearchQuery(query, config='english')

    visualisations = visualisations.annotate(search=search,
                                             search_rank=SearchRank(
                                                 search, search_query))

    if query:
        visualisations = visualisations.filter(search=search_query)

    # Mark up whether the user can access the visualisation.
    if user:
        access_filter = (Q(user_access_type='REQUIRES_AUTHENTICATION')
                         &
                         (Q(visualisationuserpermission__user=user)
                          | Q(visualisationuserpermission__isnull=True))) | Q(
                              user_access_type='REQUIRES_AUTHORIZATION',
                              visualisationuserpermission__user=user,
                          )
    else:
        access_filter = Q()

    visualisations = visualisations.annotate(_has_access=Case(
        When(access_filter, then=True),
        default=False,
        output_field=BooleanField(),
    ) if access_filter else Value(True, BooleanField()), )

    # Pull in the source tag IDs for the dataset
    visualisations = visualisations.annotate(source_tag_ids=ArrayAgg(
        'tags', filter=Q(tags__type=TagType.SOURCE.value), distinct=True))

    visualisations = visualisations.annotate(source_tag_names=ArrayAgg(
        'tags__name', filter=Q(
            tags__type=TagType.SOURCE.value), distinct=True))

    # Pull in the topic tag IDs for the dataset
    visualisations = visualisations.annotate(topic_tag_ids=ArrayAgg(
        'tags', filter=Q(tags__type=TagType.TOPIC.value), distinct=True))

    visualisations = visualisations.annotate(topic_tag_names=ArrayAgg(
        'tags__name', filter=Q(tags__type=TagType.TOPIC.value), distinct=True))

    # Define a `purpose` column denoting the dataset type
    visualisations = visualisations.annotate(
        purpose=Value(DataSetType.VISUALISATION.value, IntegerField()))

    # We are joining on the user permissions table to determine `_has_access`` to the visualisation, so we need to
    # group them and remove duplicates. We aggregate all the `_has_access` fields together and return true if any
    # of the records say that access is available.
    visualisations = visualisations.values(
        'id',
        'name',
        'slug',
        'short_description',
        'search_rank',
        'source_tag_names',
        'source_tag_ids',
        'topic_tag_names',
        'topic_tag_ids',
        'purpose',
        'published',
        'published_at',
    ).annotate(has_access=BoolOr('_has_access'))

    return visualisations.values(
        'id',
        'name',
        'slug',
        'short_description',
        'search_rank',
        'source_tag_names',
        'source_tag_ids',
        'topic_tag_names',
        'topic_tag_ids',
        'purpose',
        'published',
        'published_at',
        'has_access',
    )
Пример #11
0
def filter_datasets(
    datasets: Union[ReferenceDataset, DataSet],
    query,
    access,
    source,
    use=None,
    user=None,
):
    search = (SearchVector('name', weight='A', config='english') +
              SearchVector('short_description', weight='B', config='english') +
              SearchVector('source_tags__name', weight='B', config='english'))
    search_query = SearchQuery(query, config='english')

    dataset_filter = Q(published=True)

    if user:
        if datasets.model is ReferenceDataset:
            reference_type = DataSetType.REFERENCE.value
            reference_perm = dataset_type_to_manage_unpublished_permission_codename(
                reference_type)

            if user.has_perm(reference_perm):
                dataset_filter |= Q(published=False)

        if datasets.model is DataSet:
            master_type, datacut_type = (
                DataSetType.MASTER.value,
                DataSetType.DATACUT.value,
            )
            master_perm = dataset_type_to_manage_unpublished_permission_codename(
                master_type)
            datacut_perm = dataset_type_to_manage_unpublished_permission_codename(
                datacut_type)

            if user.has_perm(master_perm) and (not use
                                               or str(master_type) in use):
                dataset_filter |= Q(published=False, type=master_type)

            if user.has_perm(datacut_perm) and (not use
                                                or str(datacut_type) in use):
                dataset_filter |= Q(published=False, type=datacut_type)

    datasets = datasets.filter(dataset_filter).annotate(search=search,
                                                        search_rank=SearchRank(
                                                            search,
                                                            search_query))

    if user and access and datasets.model is not ReferenceDataset:
        access_filter = (Q(user_access_type='REQUIRES_AUTHENTICATION')
                         & (Q(datasetuserpermission__user=user)
                            | Q(datasetuserpermission__isnull=True))) | Q(
                                user_access_type='REQUIRES_AUTHORIZATION',
                                datasetuserpermission__user=user)
        datasets = datasets.filter(access_filter)

    if query:
        datasets = datasets.filter(search=search_query)

    if source:
        datasets = datasets.filter(source_tags__in=source)

    if use:
        datasets = datasets.filter(type__in=use)

    return datasets