Loading resources/migrations/0022_auto_20211020_0844.py +1 −1 Original line number Diff line number Diff line Loading @@ -15,4 +15,4 @@ class Migration(migrations.Migration): ("resources", "0021_auto_20211007_1748"), ] operations = [] operations = [migrations.RunPython(fixtures)] resources/migrations/0023_auto_20211020_0948.py 0 → 100644 +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)] rpc/methods.py +75 −17 Original line number Diff line number Diff line Loading @@ -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): Loading Loading @@ -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() Loading @@ -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 Loading Loading @@ -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"]) Loading Loading @@ -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: Loading @@ -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 Loading Loading @@ -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"]) Loading Loading @@ -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) Loading Loading @@ -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) Loading @@ -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 Loading Loading @@ -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) Loading @@ -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: Loading @@ -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 ( Loading Loading @@ -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 Loading Loading @@ -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 Loading Loading @@ -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. Loading Loading @@ -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() Loading Loading @@ -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" Loading rpc/serializers.py +8 −1 Original line number Diff line number Diff line Loading @@ -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)) Loading Loading @@ -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(): Loading Loading
resources/migrations/0022_auto_20211020_0844.py +1 −1 Original line number Diff line number Diff line Loading @@ -15,4 +15,4 @@ class Migration(migrations.Migration): ("resources", "0021_auto_20211007_1748"), ] operations = [] operations = [migrations.RunPython(fixtures)]
resources/migrations/0023_auto_20211020_0948.py 0 → 100644 +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)]
rpc/methods.py +75 −17 Original line number Diff line number Diff line Loading @@ -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): Loading Loading @@ -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() Loading @@ -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 Loading Loading @@ -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"]) Loading Loading @@ -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: Loading @@ -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 Loading Loading @@ -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"]) Loading Loading @@ -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) Loading Loading @@ -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) Loading @@ -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 Loading Loading @@ -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) Loading @@ -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: Loading @@ -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 ( Loading Loading @@ -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 Loading Loading @@ -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 Loading Loading @@ -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. Loading Loading @@ -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() Loading Loading @@ -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" Loading
rpc/serializers.py +8 −1 Original line number Diff line number Diff line Loading @@ -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)) Loading Loading @@ -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(): Loading