Commit 244959db authored by Mickaël Desfrênes's avatar Mickaël Desfrênes
Browse files

filter public collections

parent fbda0a64
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -15,4 +15,4 @@ class Migration(migrations.Migration):
        ("resources", "0021_auto_20211007_1748"),
    ]

    operations = []
    operations = [migrations.RunPython(fixtures)]
+17 −0
Original line number Diff line number Diff line
# Generated by Django 3.2.2 on 2021-10-20 09:48

from django.db import migrations
from resources.models import Permission


def fixtures(*args):
    Permission.objects.get_or_create(label="collection.public_only")


class Migration(migrations.Migration):

    dependencies = [
        ("resources", "0022_auto_20211020_0844"),
    ]

    operations = [migrations.RunPython(fixtures)]
+75 −17
Original line number Diff line number Diff line
@@ -29,6 +29,12 @@ from functools import wraps as _wraps


SUPERUSER_NEEDED = "only for superusers"
CAN_ONLY_SHOW_PUBLIC_COLLECTIONS_CONTENT = "can only show public collections content"
NO_SUCH_PROJECT = "no such project"
NO_SUCH_COLLECTION = "no such collection"
NO_SUCH_RESOURCE = "no such resource"
PERM_COLLECTION_PUBLIC_ONLY = "collection.public_only"
PERM_RESOURCE_READ = "resource.read"


class ServiceException(Exception):
@@ -90,7 +96,7 @@ def _check_project_permission(
        try:
            project = Project.objects.get(pk=project)
        except Project.DoesNotExist:
            raise ServiceException("no such project")
            raise ServiceException(NO_SUCH_PROJECT)
    access = ProjectAccess.objects.filter(
        user=user, project=project, role__permissions__label=permission
    ).first()
@@ -103,6 +109,16 @@ def _check_project_permission(
    )


def _user_has_permission(
    user: User, project: Union[Project, int], permission: str
) -> bool:
    try:
        _check_project_permission(user, project, permission)
        return True
    except ServiceException:
        return False


# Define RPC functions here.
# ALL RPC functions receive a User instance as first argument

@@ -149,7 +165,7 @@ def metadatasets(user: User, project_id: int) -> List[Dict]:
            data.append(serializers.metadataset(item))
        return data
    except Project.DoesNotExist:
        raise ServiceException("no such project")
        raise ServiceException(NO_SUCH_PROJECT)


@_rpc_groups(["Metadatas"])
@@ -279,7 +295,14 @@ def collections(
            )
            project_id = parent.project_id
    except Collection.DoesNotExist:
        raise ServiceException("no such collection")
        raise ServiceException(NO_SUCH_COLLECTION)
    # Special case: user only has access to public content.
    # Also block access to parent.
    public_only = _user_has_permission(user, project_id, PERM_COLLECTION_PUBLIC_ONLY)
    if public_only:
        only_published = True
        if not parent.public_access:
            raise ServiceException(CAN_ONLY_SHOW_PUBLIC_COLLECTIONS_CONTENT)
    limit_from = int(limit_from)
    limit_to = int(limit_to)
    if limit_to < limit_from:
@@ -304,7 +327,11 @@ def collections(
        query_set = query_set.filter(public_access=True)
    query_set = query_set[limit_from:limit_to]
    for item in query_set:
        data.append(serializers.collection(item, recursive=recursive))
        data.append(
            serializers.collection(
                item, recursive=recursive, only_published=only_published
            )
        )
    return data


@@ -368,8 +395,14 @@ def collection(
    collection_instance = query_set.first()
    if not collection_instance:
        return None
    public_only = _user_has_permission(
        user, collection_instance.project, PERM_COLLECTION_PUBLIC_ONLY
    )
    _check_project_permission(user, collection_instance.project, "collection.read")
    return serializers.collection(collection_instance)
    # Special case: user has limiting permission
    if public_only and not collection_instance.public_access:
        raise ServiceException(CAN_ONLY_SHOW_PUBLIC_COLLECTIONS_CONTENT)
    return serializers.collection(collection_instance, only_published=public_only)


@_rpc_groups(["Collections"])
@@ -499,7 +532,7 @@ def add_collection_from_path(user: User, path: str, project_id: int) -> List[Dic
        raise ServiceException("project_id is missing")
    project = Project.objects.filter(pk=project_id).first()
    if not project:
        raise ServiceException("no such project")
        raise ServiceException(NO_SUCH_PROJECT)
    _check_project_permission(user, project, "collection.create")
    hierarchy = []
    previous_dir = Collection.objects.get(title="root", parent=None)
@@ -691,6 +724,15 @@ def resources(
    ]
    ```
    """
    try:
        collection_instance = Collection.objects.get(pk=collection_id)
        public_only = _user_has_permission(
            user, collection_instance.project, PERM_COLLECTION_PUBLIC_ONLY
        )
        if public_only and not collection_instance.public_access:
            raise ServiceException(CAN_ONLY_SHOW_PUBLIC_COLLECTIONS_CONTENT)
    except Collection.DoesNotExist:
        raise ServiceException(NO_SUCH_COLLECTION)
    data = []
    limit_from = int(limit_from)
    limit_to = int(limit_to)
@@ -700,8 +742,9 @@ def resources(
        collections__id=collection_id,
        deleted_at__isnull=True,
        ptr_project__projectaccess__user=user,
        ptr_project__projectaccess__role__permissions__label="resource.read",
        ptr_project__projectaccess__role__permissions__label=PERM_RESOURCE_READ,
    )

    for item in query_set[limit_from:limit_to]:
        data.append(serializers.resource(item, include_metas=bool(include_metas)))
    return data
@@ -733,7 +776,16 @@ def resource(user: User, resource_id: int) -> Union[Dict, None]:
    resource_instance = query_set.first()
    if not resource_instance:
        return None
    _check_project_permission(user, resource_instance.ptr_project, "resource.read")
    # if resource in a private collection and user has limiting access right, do not expose.
    public_only = _user_has_permission(
        user, resource_instance.ptr_project, PERM_COLLECTION_PUBLIC_ONLY
    )
    if public_only:
        for collection_instance in resource_instance.collections.filter(
            public_access=False
        ):
            raise ServiceException(CAN_ONLY_SHOW_PUBLIC_COLLECTIONS_CONTENT)
    _check_project_permission(user, resource_instance.ptr_project, PERM_RESOURCE_READ)
    return serializers.resource(resource_instance)


@@ -756,13 +808,15 @@ def add_resource_to_collection(
        _check_project_permission(
            user, collection_instance.project, "collection.update"
        )
        _check_project_permission(user, resource_instance.ptr_project, "resource.read")
        _check_project_permission(
            user, resource_instance.ptr_project, PERM_RESOURCE_READ
        )
        collection_instance.resources.add(resource_instance)
        return True
    except Collection.DoesNotExist:
        raise ServiceException("no such collection")
        raise ServiceException(NO_SUCH_COLLECTION)
    except Resource.DoesNotExist:
        raise ServiceException("no such resource")
        raise ServiceException(NO_SUCH_RESOURCE)
    except Collection.MultipleObjectsReturned:
        raise ServiceException("multiple collections returned")
    except Resource.MultipleObjectsReturned:
@@ -788,7 +842,9 @@ def remove_resource_from_collection(
        _check_project_permission(
            user, collection_instance.project, "collection.update"
        )
        _check_project_permission(user, resource_instance.ptr_project, "resource.read")
        _check_project_permission(
            user, resource_instance.ptr_project, PERM_RESOURCE_READ
        )
        collection_instance.resources.remove(resource_instance)
        return True
    except (
@@ -857,7 +913,7 @@ def simple_search(user: User, query: str, project_id: int) -> Dict[str, List]:
    """
    project = Project.objects.filter(pk=project_id).first()
    _check_project_permission(user, project, "collection.read")
    _check_project_permission(user, project, "resource.read")
    _check_project_permission(user, project, PERM_RESOURCE_READ)
    results = {"collections": [], "resources": []}
    collections_set: Union[Iterator[Collection], QuerySet] = Collection.objects.filter(
        title__icontains=query, deleted_at__isnull=True, project=project
@@ -936,7 +992,7 @@ def advanced_search(
        raise ServiceException("Too many search terms.")
    project = Project.objects.filter(pk=project_id).first()
    _check_project_permission(user, project, "collection.read")
    _check_project_permission(user, project, "resource.read")
    _check_project_permission(user, project, PERM_RESOURCE_READ)
    # TODO: add tags search
    results = {"collections": [], "resources": []}
    # Search Resources first
@@ -1173,7 +1229,7 @@ def add_meta_to_resource(
            pk=resource_id,
            deleted_at__isnull=True,
            ptr_project__projectaccess__user=user,
            ptr_project__projectaccess__role__permissions__label="resource.read",
            ptr_project__projectaccess__role__permissions__label=PERM_RESOURCE_READ,
        )
        # Adding a meta value to a resource is a resource.update, NOT a metadata.update.
        # No need to go further.
@@ -1741,7 +1797,9 @@ def set_representative_resource(
        _check_project_permission(
            user, collection_instance.project, "collection.update"
        )
        _check_project_permission(user, resource_instance.ptr_project, "resource.read")
        _check_project_permission(
            user, resource_instance.ptr_project, PERM_RESOURCE_READ
        )
        if resource_instance.ptr_project_id == collection_instance.project_id:
            collection_instance.representative = resource_instance
            collection_instance.save()
@@ -1780,7 +1838,7 @@ def replace_file(user: User, from_resource_id: int, to_resource_id: int) -> bool
        if not to_resource_instance.file:
            return False
        _check_project_permission(
            user, from_resource_instance.ptr_project, "resource.read"
            user, from_resource_instance.ptr_project, PERM_RESOURCE_READ
        )
        _check_project_permission(
            user, to_resource_instance.ptr_project, "resource.update"
+8 −1
Original line number Diff line number Diff line
@@ -61,7 +61,11 @@ def metadata_resource_value(
    }


def collection(collection_instance: models.Collection, recursive: bool = False) -> dict:
def collection(
    collection_instance: models.Collection,
    recursive: bool = False,
    only_published: bool = False,
) -> dict:
    tags = []
    for tag_instance in collection_instance.tags.all():
        tags.append(tag(tag_instance))
@@ -98,6 +102,9 @@ def collection(collection_instance: models.Collection, recursive: bool = False)
    if recursive:
        payload["children"] = []
        for child in collection_instance.children():
            # filter private content
            if only_published and child.public_access == False:
                continue
            payload["children"].append(collection(child, recursive))

    for prop in collection_instance.metadatacollectionvalue_set.all():