Loading rpc/methods.py +143 −73 Original line number Diff line number Diff line Loading @@ -36,6 +36,8 @@ def _check_project_permission( - user has no access to given project/permission - project is int and no such pk exists """ if project is None: raise ServiceException("project_id is not set") if isinstance(project, int): try: project = Project.objects.get(pk=project) Loading Loading @@ -106,6 +108,9 @@ def has_permission(user: User, project_id: int, permission: str) -> bool: return False has_permission.rpc_groups = ["Utilities"] def metadatasets(user: User, project_id: int) -> List[Dict]: """ Get the list of all the project's metadata sets. Loading Loading @@ -582,21 +587,19 @@ def delete_collection(user: User, collection_id: int, recursive: bool = False) - unless the 'recursive'parameter is set to True. """ query_set: Union[Iterator[Collection], QuerySet] = Collection.objects.filter( pk=collection_id, owner=user, deleted_at__isnull=True pk=collection_id, deleted_at__isnull=True ) collection_instance = query_set.first() if not collection_instance: return {"success": True, "status": "does not exist"} _check_project_permission(user, collection_instance.project, "collection.delete") if recursive: if has_permission(user, collection_instance.project, "resource.delete"): for resource_instance in collection_instance.resources.all(): if resource_instance.ptr_owner == user: resource_instance.soft_delete() for resource_instance in collection_instance.descendants_resources(): if resource_instance.ptr_owner == user: resource_instance.soft_delete() for descendant_collection_instance in collection_instance.descendants(): if descendant_collection_instance.owner == user: descendant_collection_instance.soft_delete() # do not allow to delete collection with content Loading @@ -616,12 +619,12 @@ def rename_collection(user: User, collection_id: int, title: str) -> bool: Rename a collection (ie. change its title). """ query_set: Union[Iterator[Collection], QuerySet] = Collection.objects.filter( pk=collection_id, owner=user, deleted_at__isnull=True pk=collection_id, deleted_at__isnull=True ) collection_instance = query_set.first() if not collection_instance: return False _check_project_permission(user, collection_instance.project, "collection.rename") _check_project_permission(user, collection_instance.project, "collection.write") collection_instance.title = title collection_instance.save() return True Loading @@ -635,12 +638,12 @@ def rename_resource(user: User, resource_id: int, title: str) -> bool: Rename a resource (ie. change its title). """ query_set: Union[Iterator[Resource], QuerySet] = Resource.objects.filter( pk=resource_id, ptr_owner=user, deleted_at__isnull=True pk=resource_id, deleted_at__isnull=True ) resource_instance = query_set.first() if not resource_instance: return False _check_project_permission(user, resource_instance.project, "resource.rename") _check_project_permission(user, resource_instance.project, "resource.write") resource_instance.title = title resource_instance.save() return True Loading @@ -653,13 +656,11 @@ def rename_meta(user: User, meta_id: int, title: str) -> bool: """ Rename a metadata (ie. change its title). """ query_set: Union[Iterator[Metadata], QuerySet] = Metadata.objects.filter( pk=meta_id, owner=user ) query_set: Union[Iterator[Metadata], QuerySet] = Metadata.objects.filter(pk=meta_id) meta_instance = query_set.first() if not meta_instance: return False _check_project_permission(user, meta_instance.project, "metadata.rename") _check_project_permission(user, meta_instance.project, "metadata.write") meta_instance.title = title meta_instance.save() return True Loading Loading @@ -707,7 +708,10 @@ def resources( if limit_to < limit_from: return [] query_set: Union[Iterator[Resource], QuerySet] = Resource.objects.filter( collections__id=collection_id, ptr_owner=user, deleted_at__isnull=True collections__id=collection_id, deleted_at__isnull=True, ptr_project__projectaccess__user=user, ptr_project__projectaccess__role__permissions__label="resource.read", ) for item in query_set[limit_from:limit_to]: data.append(serializers.resource(item, include_metas=bool(include_metas))) Loading Loading @@ -737,11 +741,12 @@ def resource(user: User, resource_id: int) -> Union[Dict, None]: ``` """ query_set: Union[Iterator[Resource], QuerySet] = Resource.objects.filter( pk=resource_id, ptr_owner=user, deleted_at__isnull=True pk=resource_id, deleted_at__isnull=True ) resource_instance = query_set.first() if not resource_instance: return None _check_project_permission(user, resource_instance.ptr_project, "resource.read") return serializers.resource(resource_instance) Loading @@ -756,11 +761,15 @@ def add_resource_to_collection( """ try: collection_instance = Collection.objects.get( owner=user, id=collection_id, deleted_at__isnull=True id=collection_id, deleted_at__isnull=True ) resource_instance = Resource.objects.get( ptr_owner=user, id=resource_id, deleted_at__isnull=True id=resource_id, deleted_at__isnull=True, ptr_project=collection_instance.project, ) _check_project_permission(user, collection_instance.project, "collection.write") _check_project_permission(user, resource_instance.ptr_project, "resource.read") collection_instance.resources.add(resource_instance) return True except ( Loading @@ -783,11 +792,15 @@ def remove_resource_from_collection( """ try: collection_instance = Collection.objects.get( owner=user, id=collection_id, deleted_at__isnull=True id=collection_id, deleted_at__isnull=True ) resource_instance = Resource.objects.get( ptr_owner=user, id=resource_id, deleted_at__isnull=True id=resource_id, deleted_at__isnull=True, ptr_project=collection_instance.project, ) _check_project_permission(user, collection_instance.project, "collection.write") _check_project_permission(user, resource_instance.ptr_project, "resource.read") collection_instance.resources.remove(resource_instance) return True except ( Loading @@ -806,13 +819,13 @@ def delete_resource(user: User, resource_id: int) -> bool: """ Permanently delete a resource given its id. """ # TODO: remove file on drive if last owner query_set: Union[Iterator[Resource], QuerySet] = Resource.objects.filter( pk=resource_id, ptr_owner=user, deleted_at__isnull=True pk=resource_id, deleted_at__isnull=True ) resource_instance = query_set.first() if not resource_instance: return True _check_project_permission(user, resource_instance.ptr_project, "resource.delete") resource_instance.soft_delete() return True Loading @@ -820,7 +833,7 @@ def delete_resource(user: User, resource_id: int) -> bool: delete_resource.rpc_groups = ["Resources"] def simple_search(user: User, query: str) -> Dict[str, List]: def simple_search(user: User, query: str, project_id: int) -> Dict[str, List]: """ Performs a simple search on resources and collections, based on their titles. Loading Loading @@ -858,14 +871,17 @@ def simple_search(user: User, query: str) -> 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") results = {"collections": [], "resources": []} collections_set: Union[Iterator[Collection], QuerySet] = Collection.objects.filter( owner=user, title__icontains=query, deleted_at__isnull=True title__icontains=query, deleted_at__isnull=True, project=project ) for collection_instance in collections_set.distinct(): results["collections"].append(serializers.collection(collection_instance)) resources_set: Union[Iterator[Resource], QuerySet] = Resource.objects.filter( ptr_owner=user, title__icontains=query, deleted_at__isnull=True title__icontains=query, deleted_at__isnull=True, ptr_project=project ) for resource_instance in resources_set.distinct(): results["resources"].append( Loading Loading @@ -898,7 +914,9 @@ def advanced_search_terms(user: User) -> List[str]: advanced_search_terms.rpc_groups = ["Search"] def advanced_search(user: User, search_terms: List[Dict]) -> Dict[str, List]: def advanced_search( user: User, search_terms: List[Dict], project_id: int ) -> Dict[str, List]: """ Performs a complex search using terms such as 'contains', 'is', 'does_not_contain'. Loading Loading @@ -936,10 +954,15 @@ def advanced_search(user: User, search_terms: List[Dict]) -> Dict[str, List]: """ if len(search_terms) > 10: 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") # TODO: add tags search results = {"collections": [], "resources": []} # Search Resources first resources_set = Resource.objects.filter(ptr_owner=user, deleted_at__isnull=True) resources_set = Resource.objects.filter( ptr_project=project, deleted_at__isnull=True ) for search_term in search_terms: if ( "property" in search_term Loading Loading @@ -983,7 +1006,9 @@ def advanced_search(user: User, search_terms: List[Dict]) -> Dict[str, List]: ) # Search collections second collections_set = Collection.objects.filter(owner=user, deleted_at__isnull=True) collections_set = Collection.objects.filter( project=project, deleted_at__isnull=True ) for search_term in search_terms: if ( "property" in search_term Loading Loading @@ -1030,7 +1055,7 @@ def advanced_search(user: User, search_terms: List[Dict]) -> Dict[str, List]: advanced_search.rpc_groups = ["Search"] def upload_infos(user: User, sha256_hash: str) -> Dict: def upload_infos(user: User, sha256_hash: str, project_id: int) -> Dict: """ Get information for an upload based on the file hash. Loading @@ -1048,9 +1073,11 @@ def upload_infos(user: User, sha256_hash: str) -> Dict: """ infos = {"status": "not available", "id": None, "available_chunks": []} if re.match("[A-Fa-f0-9]{64}", sha256_hash) is not None: project = Project.objects.filter(pk=project_id).first() _check_project_permission(user, project, "file.read") try: file_instance = File.objects.get( hash=sha256_hash, owner=user, deleted_at__isnull=True hash=sha256_hash, project=project, deleted_at__isnull=True ) infos["status"] = "available" infos["id"] = file_instance.id Loading Loading @@ -1094,12 +1121,14 @@ def supported_file_types(user: User) -> List[Dict]: supported_file_types.rpc_groups = ["Utilities"] def add_metadataset(user: User, title: str) -> int: def add_metadataset(user: User, title: str, project_id: int) -> int: """ Create new metadata set from title. """ project = Project.objects.filter(pk=project_id).first() _check_project_permission(user, project, "metadataset.add") metadataset_instance, created = MetadataSet.objects.get_or_create( owner=user, title=title project=project, title=title ) return metadataset_instance.id Loading @@ -1121,8 +1150,9 @@ def add_metadata( meta_type = MetadataType.objects.get(pk=metadata_type_id) else: meta_type = None _check_project_permission(user, metas_set.project, "metadata.add") metadata_instance, created = Metadata.objects.get_or_create( owner=user, title=title, set=metas_set, data_type=meta_type project=metas_set.project, title=title, set=metas_set, data_type=meta_type ) return metadata_instance.id except ( Loading @@ -1142,11 +1172,13 @@ def remove_meta_from_resource(user: User, resource_id: int, meta_value_id: int) Remove a meta from a resource given their ids. """ query_set: Union[Iterator[Resource], QuerySet] = Resource.objects.filter( pk=resource_id, ptr_owner=user, deleted_at__isnull=True pk=resource_id, deleted_at__isnull=True ) resource_instance = query_set.first() if not resource_instance: return False # this is a resource.write permission, not a metadata.write _check_project_permission(user, resource_instance.ptr_project, "resource.write") for meta_value in resource_instance.metadataresourcevalue_set.all(): if meta_value.id == meta_value_id: meta_value.delete() Loading Loading @@ -1203,11 +1235,12 @@ def remove_meta_from_collection( Remove a meta from a collection given their ids. """ query_set: Union[Iterator[Collection], QuerySet] = Collection.objects.filter( pk=collection_id, owner=user, deleted_at__isnull=True pk=collection_id, deleted_at__isnull=True ) collection_instance = query_set.first() if not collection_instance: return False _check_project_permission(user, collection_instance.project, "collection.write") for meta_value in collection_instance.metadatacollectionvalue_set.all(): if meta_value.id == meta_value_id: meta_value.delete() Loading Loading @@ -1263,8 +1296,9 @@ def change_collection_meta_value( """ try: meta_value_instance = MetadataCollectionValue.objects.get(pk=meta_value_id) if meta_value_instance.collection.owner.id != user.id: return False _check_project_permission( user, meta_value_instance.metadata.project, "collection.write" ) meta_value_instance.value = meta_value meta_value_instance.save() return True Loading @@ -1281,8 +1315,9 @@ def change_resource_meta_value(user: User, meta_value_id: int, meta_value: str) """ try: meta_value_instance = MetadataResourceValue.objects.get(pk=meta_value_id) if meta_value_instance.resource.ptr_owner_id != user.id: return False _check_project_permission( user, meta_value_instance.metadata.project, "resource.write" ) meta_value_instance.value = meta_value meta_value_instance.save() return True Loading Loading @@ -1349,16 +1384,18 @@ def ancestors_from_collection( """ breadcrumb = [] query_set: Union[Iterator[Collection], QuerySet] = Collection.objects.filter( pk=collection_id, owner=user, deleted_at__isnull=True pk=collection_id, deleted_at__isnull=True ) collection_instance: Collection = query_set.first() project = collection_instance.project _check_project_permission(user, project, "collection.read") if not collection_instance: return breadcrumb current_collection = collection_instance while True: if current_collection.parent: if ( current_collection.parent.owner == user current_collection.parent.project == project and not current_collection.deleted_at ): breadcrumb.append( Loading Loading @@ -1428,13 +1465,15 @@ def ancestors_from_resource(user: User, resource_id: int) -> List[List[dict]]: """ ancestors = [] query_set: Union[Iterator[Resource], QuerySet] = Resource.objects.filter( pk=resource_id, ptr_owner=user, deleted_at__isnull=True pk=resource_id, deleted_at__isnull=True ) resource_instance = query_set.first() if not resource_instance: return ancestors project = resource_instance.ptr_project _check_project_permission(user, project, "collection.read") for collection_instance in resource_instance.collections.all(): if collection_instance.owner == user: if collection_instance.project == project: ancestors.append( ancestors_from_collection( user, collection_instance.id, include_self=True Loading Loading @@ -1473,11 +1512,12 @@ def publish_collection(user: User, collection_id: int) -> bool: Mark a collection as public """ query_set: Union[Iterator[Collection], QuerySet] = Collection.objects.filter( pk=collection_id, owner=user, deleted_at__isnull=True pk=collection_id, deleted_at__isnull=True ) collection_instance: Collection = query_set.first() if not collection_instance: return False _check_project_permission(user, collection_instance.project, "collection.write") collection_instance.public_access = True collection_instance.save() return True Loading @@ -1491,11 +1531,12 @@ def unpublish_collection(user: User, collection_id: int) -> bool: Mark a collection as private """ query_set: Union[Iterator[Collection], QuerySet] = Collection.objects.filter( pk=collection_id, owner=user, deleted_at__isnull=True pk=collection_id, deleted_at__isnull=True ) collection_instance: Collection = query_set.first() if not collection_instance: return False _check_project_permission(user, collection_instance.project, "collection.write") collection_instance.public_access = False collection_instance.save() return True Loading @@ -1521,7 +1562,7 @@ def move_collection( if child_collection_id == parent_collection_id: # no loop ! return False query_set: Union[Iterator[Collection], QuerySet] = Collection.objects.filter( pk=child_collection_id, owner=user, deleted_at__isnull=True pk=child_collection_id, deleted_at__isnull=True ) child_collection_instance: Collection = query_set.first() if not child_collection_instance: Loading @@ -1533,7 +1574,7 @@ def move_collection( ) else: query_set: Union[Iterator[Collection], QuerySet] = Collection.objects.filter( pk=parent_collection_id, owner=user, deleted_at__isnull=True pk=parent_collection_id, deleted_at__isnull=True ) parent_collection_instance: Collection = query_set.first() if not parent_collection_instance: Loading @@ -1541,6 +1582,12 @@ def move_collection( if parent_collection_instance in child_collection_instance.descendants(): return False # don't cut the branch ! _check_project_permission( user, parent_collection_instance.project, "collection.read" ) _check_project_permission( user, child_collection_instance.project, "collection.write" ) child_collection_instance.parent = parent_collection_instance child_collection_instance.save() return True Loading @@ -1549,7 +1596,9 @@ def move_collection( move_collection.rpc_groups = ["Collections"] def set_tag(user: User, uid: str, label: str = None, ark: str = None) -> dict: def set_tag( user: User, uid: str, project_id: int, label: str = None, ark: str = None ) -> dict: """ Get or create a Tag by uid (unique identifier). 'label' is an optional human-readable name. Loading @@ -1564,7 +1613,9 @@ def set_tag(user: User, uid: str, label: str = None, ark: str = None) -> dict: } ``` """ tag_instance, created = Tag.objects.get_or_create(owner=user, uid=uid) project = Project.objects.filter(pk=project_id).filter() _check_project_permission(user, project, "tag.add") tag_instance, created = Tag.objects.get_or_create(project=project, uid=uid) tag_instance.ark = ark tag_instance.label = label tag_instance.save() Loading @@ -1581,7 +1632,8 @@ def remove_tag(user: User, uid: str) -> bool: Beware: This will remove ALL associations with the tag. """ try: tag_instance = Tag.objects.get(uid=uid, owner=user) tag_instance = Tag.objects.get(uid=uid) _check_project_permission(user, tag_instance.project, "tag.delete") tag_instance.delete() return True except (Tag.DoesNotExist, Tag.MultipleObjectsReturned): Loading @@ -1591,9 +1643,9 @@ def remove_tag(user: User, uid: str) -> bool: remove_tag.rpc_groups = ["Tags"] def tags(user: User) -> List[dict]: def tags(user: User, project_id: int) -> List[dict]: """ Returns all tags available to the current user. Returns all tags available in the project. Example output: Loading @@ -1614,8 +1666,10 @@ def tags(user: User) -> List[dict]: ] ``` """ project = Project.objects.filter(project_id).first() _check_project_permission(user, project, "tag.read") tags_list = [] for tag_instance in Tag.objects.filter(owner=user): for tag_instance in Tag.objects.filter(project=project): tags_list.append(serializers.tag(tag_instance)) return tags_list Loading @@ -1629,9 +1683,11 @@ def add_tag_to_collection(user: User, tag_uid: str, collection_id: int) -> bool: """ try: collection_instance = Collection.objects.get( owner=user, id=collection_id, deleted_at__isnull=True pk=collection_id, deleted_at__isnull=True ) tag_instance = Tag.objects.get(owner=user, uid=tag_uid) project = collection_instance.project _check_project_permission(user, project, "collection.write") tag_instance = Tag.objects.get(project=project, uid=tag_uid) collection_instance.tags.add(tag_instance) return True except ( Loading @@ -1652,9 +1708,11 @@ def remove_tag_from_collection(user: User, tag_uid: str, collection_id: int) -> """ try: collection_instance = Collection.objects.get( owner=user, id=collection_id, deleted_at__isnull=True pk=collection_id, deleted_at__isnull=True ) tag_instance = Tag.objects.get(owner=user, uid=tag_uid) project = collection_instance.project _check_project_permission(user, project, "collection.write") tag_instance = Tag.objects.get(project=project, uid=tag_uid) collection_instance.tags.remove(tag_instance) return True except ( Loading @@ -1675,9 +1733,11 @@ def add_tag_to_resource(user: User, tag_uid: str, resource_id: int) -> bool: """ try: resource_instance = Resource.objects.get( ptr_owner=user, id=resource_id, deleted_at__isnull=True id=resource_id, deleted_at__isnull=True ) tag_instance = Tag.objects.get(owner=user, uid=tag_uid) project = resource_instance.ptr_project _check_project_permission(user, project, "resource.write") tag_instance = Tag.objects.get(project=project, uid=tag_uid) resource_instance.tags.add(tag_instance) return True except ( Loading @@ -1698,9 +1758,11 @@ def remove_tag_from_resource(user: User, tag_uid: str, resource_id: int) -> bool """ try: resource_instance = Resource.objects.get( ptr_owner=user, id=resource_id, deleted_at__isnull=True id=resource_id, deleted_at__isnull=True ) tag_instance = Tag.objects.get(owner=user, uid=tag_uid) project = resource_instance.ptr_project _check_project_permission(user, project, "resource.write") tag_instance = Tag.objects.get(project=project, uid=tag_uid) resource_instance.tags.remove(tag_instance) return True except ( Loading Loading @@ -1781,18 +1843,22 @@ def set_representative_resource( """ try: collection_instance = Collection.objects.get( pk=collection_id, owner=user, deleted_at__isnull=True pk=collection_id, deleted_at__isnull=True ) if not resource_id: collection_instance.representative = None collection_instance.save() return True resource_instance = Resource.objects.get( pk=resource_id, ptr_owner=user, deleted_at__isnull=True pk=resource_id, deleted_at__isnull=True ) _check_project_permission(user, collection_instance.project, "collection.write") _check_project_permission(user, resource_instance.ptr_project, "resource.read") if resource_instance.ptr_project_id == collection_instance.project_id: collection_instance.representative = resource_instance collection_instance.save() return True return False except (Collection.DoesNotExist, Resource.DoesNotExist): return False Loading @@ -1818,18 +1884,21 @@ def replace_file(user: User, from_resource_id: int, to_resource_id: int) -> bool """ try: from_resource_instance = Resource.objects.get( ptr_owner=user, pk=from_resource_id, deleted_at__isnull=True pk=from_resource_id, deleted_at__isnull=True ) if not from_resource_instance.file: return False to_resource_instance = Resource.objects.get( ptr_owner=user, pk=to_resource_id, deleted_at__isnull=True pk=to_resource_id, deleted_at__isnull=True ) if not to_resource_instance.file: return False _check_project_permission( user, from_resource_instance.ptr_project, "resource.read" ) _check_project_permission( user, to_resource_instance.ptr_project, "resource.write" ) try: exif_set = MetadataSet.objects.get(title="ExifTool") # remove to_resource exif metas Loading Loading @@ -1872,7 +1941,8 @@ def set_is_oai_record( will be used in OAI-PMH requests. """ try: collection_instance = Collection.objects.get(pk=collection_id, owner=user) collection_instance = Collection.objects.get(pk=collection_id) _check_project_permission(user, collection_instance.project, "collection.write") collection_instance.is_oai_record = is_oai_record # TODO: fetch and save ARK identifier collection_instance.save() Loading Loading
rpc/methods.py +143 −73 Original line number Diff line number Diff line Loading @@ -36,6 +36,8 @@ def _check_project_permission( - user has no access to given project/permission - project is int and no such pk exists """ if project is None: raise ServiceException("project_id is not set") if isinstance(project, int): try: project = Project.objects.get(pk=project) Loading Loading @@ -106,6 +108,9 @@ def has_permission(user: User, project_id: int, permission: str) -> bool: return False has_permission.rpc_groups = ["Utilities"] def metadatasets(user: User, project_id: int) -> List[Dict]: """ Get the list of all the project's metadata sets. Loading Loading @@ -582,21 +587,19 @@ def delete_collection(user: User, collection_id: int, recursive: bool = False) - unless the 'recursive'parameter is set to True. """ query_set: Union[Iterator[Collection], QuerySet] = Collection.objects.filter( pk=collection_id, owner=user, deleted_at__isnull=True pk=collection_id, deleted_at__isnull=True ) collection_instance = query_set.first() if not collection_instance: return {"success": True, "status": "does not exist"} _check_project_permission(user, collection_instance.project, "collection.delete") if recursive: if has_permission(user, collection_instance.project, "resource.delete"): for resource_instance in collection_instance.resources.all(): if resource_instance.ptr_owner == user: resource_instance.soft_delete() for resource_instance in collection_instance.descendants_resources(): if resource_instance.ptr_owner == user: resource_instance.soft_delete() for descendant_collection_instance in collection_instance.descendants(): if descendant_collection_instance.owner == user: descendant_collection_instance.soft_delete() # do not allow to delete collection with content Loading @@ -616,12 +619,12 @@ def rename_collection(user: User, collection_id: int, title: str) -> bool: Rename a collection (ie. change its title). """ query_set: Union[Iterator[Collection], QuerySet] = Collection.objects.filter( pk=collection_id, owner=user, deleted_at__isnull=True pk=collection_id, deleted_at__isnull=True ) collection_instance = query_set.first() if not collection_instance: return False _check_project_permission(user, collection_instance.project, "collection.rename") _check_project_permission(user, collection_instance.project, "collection.write") collection_instance.title = title collection_instance.save() return True Loading @@ -635,12 +638,12 @@ def rename_resource(user: User, resource_id: int, title: str) -> bool: Rename a resource (ie. change its title). """ query_set: Union[Iterator[Resource], QuerySet] = Resource.objects.filter( pk=resource_id, ptr_owner=user, deleted_at__isnull=True pk=resource_id, deleted_at__isnull=True ) resource_instance = query_set.first() if not resource_instance: return False _check_project_permission(user, resource_instance.project, "resource.rename") _check_project_permission(user, resource_instance.project, "resource.write") resource_instance.title = title resource_instance.save() return True Loading @@ -653,13 +656,11 @@ def rename_meta(user: User, meta_id: int, title: str) -> bool: """ Rename a metadata (ie. change its title). """ query_set: Union[Iterator[Metadata], QuerySet] = Metadata.objects.filter( pk=meta_id, owner=user ) query_set: Union[Iterator[Metadata], QuerySet] = Metadata.objects.filter(pk=meta_id) meta_instance = query_set.first() if not meta_instance: return False _check_project_permission(user, meta_instance.project, "metadata.rename") _check_project_permission(user, meta_instance.project, "metadata.write") meta_instance.title = title meta_instance.save() return True Loading Loading @@ -707,7 +708,10 @@ def resources( if limit_to < limit_from: return [] query_set: Union[Iterator[Resource], QuerySet] = Resource.objects.filter( collections__id=collection_id, ptr_owner=user, deleted_at__isnull=True collections__id=collection_id, deleted_at__isnull=True, ptr_project__projectaccess__user=user, ptr_project__projectaccess__role__permissions__label="resource.read", ) for item in query_set[limit_from:limit_to]: data.append(serializers.resource(item, include_metas=bool(include_metas))) Loading Loading @@ -737,11 +741,12 @@ def resource(user: User, resource_id: int) -> Union[Dict, None]: ``` """ query_set: Union[Iterator[Resource], QuerySet] = Resource.objects.filter( pk=resource_id, ptr_owner=user, deleted_at__isnull=True pk=resource_id, deleted_at__isnull=True ) resource_instance = query_set.first() if not resource_instance: return None _check_project_permission(user, resource_instance.ptr_project, "resource.read") return serializers.resource(resource_instance) Loading @@ -756,11 +761,15 @@ def add_resource_to_collection( """ try: collection_instance = Collection.objects.get( owner=user, id=collection_id, deleted_at__isnull=True id=collection_id, deleted_at__isnull=True ) resource_instance = Resource.objects.get( ptr_owner=user, id=resource_id, deleted_at__isnull=True id=resource_id, deleted_at__isnull=True, ptr_project=collection_instance.project, ) _check_project_permission(user, collection_instance.project, "collection.write") _check_project_permission(user, resource_instance.ptr_project, "resource.read") collection_instance.resources.add(resource_instance) return True except ( Loading @@ -783,11 +792,15 @@ def remove_resource_from_collection( """ try: collection_instance = Collection.objects.get( owner=user, id=collection_id, deleted_at__isnull=True id=collection_id, deleted_at__isnull=True ) resource_instance = Resource.objects.get( ptr_owner=user, id=resource_id, deleted_at__isnull=True id=resource_id, deleted_at__isnull=True, ptr_project=collection_instance.project, ) _check_project_permission(user, collection_instance.project, "collection.write") _check_project_permission(user, resource_instance.ptr_project, "resource.read") collection_instance.resources.remove(resource_instance) return True except ( Loading @@ -806,13 +819,13 @@ def delete_resource(user: User, resource_id: int) -> bool: """ Permanently delete a resource given its id. """ # TODO: remove file on drive if last owner query_set: Union[Iterator[Resource], QuerySet] = Resource.objects.filter( pk=resource_id, ptr_owner=user, deleted_at__isnull=True pk=resource_id, deleted_at__isnull=True ) resource_instance = query_set.first() if not resource_instance: return True _check_project_permission(user, resource_instance.ptr_project, "resource.delete") resource_instance.soft_delete() return True Loading @@ -820,7 +833,7 @@ def delete_resource(user: User, resource_id: int) -> bool: delete_resource.rpc_groups = ["Resources"] def simple_search(user: User, query: str) -> Dict[str, List]: def simple_search(user: User, query: str, project_id: int) -> Dict[str, List]: """ Performs a simple search on resources and collections, based on their titles. Loading Loading @@ -858,14 +871,17 @@ def simple_search(user: User, query: str) -> 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") results = {"collections": [], "resources": []} collections_set: Union[Iterator[Collection], QuerySet] = Collection.objects.filter( owner=user, title__icontains=query, deleted_at__isnull=True title__icontains=query, deleted_at__isnull=True, project=project ) for collection_instance in collections_set.distinct(): results["collections"].append(serializers.collection(collection_instance)) resources_set: Union[Iterator[Resource], QuerySet] = Resource.objects.filter( ptr_owner=user, title__icontains=query, deleted_at__isnull=True title__icontains=query, deleted_at__isnull=True, ptr_project=project ) for resource_instance in resources_set.distinct(): results["resources"].append( Loading Loading @@ -898,7 +914,9 @@ def advanced_search_terms(user: User) -> List[str]: advanced_search_terms.rpc_groups = ["Search"] def advanced_search(user: User, search_terms: List[Dict]) -> Dict[str, List]: def advanced_search( user: User, search_terms: List[Dict], project_id: int ) -> Dict[str, List]: """ Performs a complex search using terms such as 'contains', 'is', 'does_not_contain'. Loading Loading @@ -936,10 +954,15 @@ def advanced_search(user: User, search_terms: List[Dict]) -> Dict[str, List]: """ if len(search_terms) > 10: 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") # TODO: add tags search results = {"collections": [], "resources": []} # Search Resources first resources_set = Resource.objects.filter(ptr_owner=user, deleted_at__isnull=True) resources_set = Resource.objects.filter( ptr_project=project, deleted_at__isnull=True ) for search_term in search_terms: if ( "property" in search_term Loading Loading @@ -983,7 +1006,9 @@ def advanced_search(user: User, search_terms: List[Dict]) -> Dict[str, List]: ) # Search collections second collections_set = Collection.objects.filter(owner=user, deleted_at__isnull=True) collections_set = Collection.objects.filter( project=project, deleted_at__isnull=True ) for search_term in search_terms: if ( "property" in search_term Loading Loading @@ -1030,7 +1055,7 @@ def advanced_search(user: User, search_terms: List[Dict]) -> Dict[str, List]: advanced_search.rpc_groups = ["Search"] def upload_infos(user: User, sha256_hash: str) -> Dict: def upload_infos(user: User, sha256_hash: str, project_id: int) -> Dict: """ Get information for an upload based on the file hash. Loading @@ -1048,9 +1073,11 @@ def upload_infos(user: User, sha256_hash: str) -> Dict: """ infos = {"status": "not available", "id": None, "available_chunks": []} if re.match("[A-Fa-f0-9]{64}", sha256_hash) is not None: project = Project.objects.filter(pk=project_id).first() _check_project_permission(user, project, "file.read") try: file_instance = File.objects.get( hash=sha256_hash, owner=user, deleted_at__isnull=True hash=sha256_hash, project=project, deleted_at__isnull=True ) infos["status"] = "available" infos["id"] = file_instance.id Loading Loading @@ -1094,12 +1121,14 @@ def supported_file_types(user: User) -> List[Dict]: supported_file_types.rpc_groups = ["Utilities"] def add_metadataset(user: User, title: str) -> int: def add_metadataset(user: User, title: str, project_id: int) -> int: """ Create new metadata set from title. """ project = Project.objects.filter(pk=project_id).first() _check_project_permission(user, project, "metadataset.add") metadataset_instance, created = MetadataSet.objects.get_or_create( owner=user, title=title project=project, title=title ) return metadataset_instance.id Loading @@ -1121,8 +1150,9 @@ def add_metadata( meta_type = MetadataType.objects.get(pk=metadata_type_id) else: meta_type = None _check_project_permission(user, metas_set.project, "metadata.add") metadata_instance, created = Metadata.objects.get_or_create( owner=user, title=title, set=metas_set, data_type=meta_type project=metas_set.project, title=title, set=metas_set, data_type=meta_type ) return metadata_instance.id except ( Loading @@ -1142,11 +1172,13 @@ def remove_meta_from_resource(user: User, resource_id: int, meta_value_id: int) Remove a meta from a resource given their ids. """ query_set: Union[Iterator[Resource], QuerySet] = Resource.objects.filter( pk=resource_id, ptr_owner=user, deleted_at__isnull=True pk=resource_id, deleted_at__isnull=True ) resource_instance = query_set.first() if not resource_instance: return False # this is a resource.write permission, not a metadata.write _check_project_permission(user, resource_instance.ptr_project, "resource.write") for meta_value in resource_instance.metadataresourcevalue_set.all(): if meta_value.id == meta_value_id: meta_value.delete() Loading Loading @@ -1203,11 +1235,12 @@ def remove_meta_from_collection( Remove a meta from a collection given their ids. """ query_set: Union[Iterator[Collection], QuerySet] = Collection.objects.filter( pk=collection_id, owner=user, deleted_at__isnull=True pk=collection_id, deleted_at__isnull=True ) collection_instance = query_set.first() if not collection_instance: return False _check_project_permission(user, collection_instance.project, "collection.write") for meta_value in collection_instance.metadatacollectionvalue_set.all(): if meta_value.id == meta_value_id: meta_value.delete() Loading Loading @@ -1263,8 +1296,9 @@ def change_collection_meta_value( """ try: meta_value_instance = MetadataCollectionValue.objects.get(pk=meta_value_id) if meta_value_instance.collection.owner.id != user.id: return False _check_project_permission( user, meta_value_instance.metadata.project, "collection.write" ) meta_value_instance.value = meta_value meta_value_instance.save() return True Loading @@ -1281,8 +1315,9 @@ def change_resource_meta_value(user: User, meta_value_id: int, meta_value: str) """ try: meta_value_instance = MetadataResourceValue.objects.get(pk=meta_value_id) if meta_value_instance.resource.ptr_owner_id != user.id: return False _check_project_permission( user, meta_value_instance.metadata.project, "resource.write" ) meta_value_instance.value = meta_value meta_value_instance.save() return True Loading Loading @@ -1349,16 +1384,18 @@ def ancestors_from_collection( """ breadcrumb = [] query_set: Union[Iterator[Collection], QuerySet] = Collection.objects.filter( pk=collection_id, owner=user, deleted_at__isnull=True pk=collection_id, deleted_at__isnull=True ) collection_instance: Collection = query_set.first() project = collection_instance.project _check_project_permission(user, project, "collection.read") if not collection_instance: return breadcrumb current_collection = collection_instance while True: if current_collection.parent: if ( current_collection.parent.owner == user current_collection.parent.project == project and not current_collection.deleted_at ): breadcrumb.append( Loading Loading @@ -1428,13 +1465,15 @@ def ancestors_from_resource(user: User, resource_id: int) -> List[List[dict]]: """ ancestors = [] query_set: Union[Iterator[Resource], QuerySet] = Resource.objects.filter( pk=resource_id, ptr_owner=user, deleted_at__isnull=True pk=resource_id, deleted_at__isnull=True ) resource_instance = query_set.first() if not resource_instance: return ancestors project = resource_instance.ptr_project _check_project_permission(user, project, "collection.read") for collection_instance in resource_instance.collections.all(): if collection_instance.owner == user: if collection_instance.project == project: ancestors.append( ancestors_from_collection( user, collection_instance.id, include_self=True Loading Loading @@ -1473,11 +1512,12 @@ def publish_collection(user: User, collection_id: int) -> bool: Mark a collection as public """ query_set: Union[Iterator[Collection], QuerySet] = Collection.objects.filter( pk=collection_id, owner=user, deleted_at__isnull=True pk=collection_id, deleted_at__isnull=True ) collection_instance: Collection = query_set.first() if not collection_instance: return False _check_project_permission(user, collection_instance.project, "collection.write") collection_instance.public_access = True collection_instance.save() return True Loading @@ -1491,11 +1531,12 @@ def unpublish_collection(user: User, collection_id: int) -> bool: Mark a collection as private """ query_set: Union[Iterator[Collection], QuerySet] = Collection.objects.filter( pk=collection_id, owner=user, deleted_at__isnull=True pk=collection_id, deleted_at__isnull=True ) collection_instance: Collection = query_set.first() if not collection_instance: return False _check_project_permission(user, collection_instance.project, "collection.write") collection_instance.public_access = False collection_instance.save() return True Loading @@ -1521,7 +1562,7 @@ def move_collection( if child_collection_id == parent_collection_id: # no loop ! return False query_set: Union[Iterator[Collection], QuerySet] = Collection.objects.filter( pk=child_collection_id, owner=user, deleted_at__isnull=True pk=child_collection_id, deleted_at__isnull=True ) child_collection_instance: Collection = query_set.first() if not child_collection_instance: Loading @@ -1533,7 +1574,7 @@ def move_collection( ) else: query_set: Union[Iterator[Collection], QuerySet] = Collection.objects.filter( pk=parent_collection_id, owner=user, deleted_at__isnull=True pk=parent_collection_id, deleted_at__isnull=True ) parent_collection_instance: Collection = query_set.first() if not parent_collection_instance: Loading @@ -1541,6 +1582,12 @@ def move_collection( if parent_collection_instance in child_collection_instance.descendants(): return False # don't cut the branch ! _check_project_permission( user, parent_collection_instance.project, "collection.read" ) _check_project_permission( user, child_collection_instance.project, "collection.write" ) child_collection_instance.parent = parent_collection_instance child_collection_instance.save() return True Loading @@ -1549,7 +1596,9 @@ def move_collection( move_collection.rpc_groups = ["Collections"] def set_tag(user: User, uid: str, label: str = None, ark: str = None) -> dict: def set_tag( user: User, uid: str, project_id: int, label: str = None, ark: str = None ) -> dict: """ Get or create a Tag by uid (unique identifier). 'label' is an optional human-readable name. Loading @@ -1564,7 +1613,9 @@ def set_tag(user: User, uid: str, label: str = None, ark: str = None) -> dict: } ``` """ tag_instance, created = Tag.objects.get_or_create(owner=user, uid=uid) project = Project.objects.filter(pk=project_id).filter() _check_project_permission(user, project, "tag.add") tag_instance, created = Tag.objects.get_or_create(project=project, uid=uid) tag_instance.ark = ark tag_instance.label = label tag_instance.save() Loading @@ -1581,7 +1632,8 @@ def remove_tag(user: User, uid: str) -> bool: Beware: This will remove ALL associations with the tag. """ try: tag_instance = Tag.objects.get(uid=uid, owner=user) tag_instance = Tag.objects.get(uid=uid) _check_project_permission(user, tag_instance.project, "tag.delete") tag_instance.delete() return True except (Tag.DoesNotExist, Tag.MultipleObjectsReturned): Loading @@ -1591,9 +1643,9 @@ def remove_tag(user: User, uid: str) -> bool: remove_tag.rpc_groups = ["Tags"] def tags(user: User) -> List[dict]: def tags(user: User, project_id: int) -> List[dict]: """ Returns all tags available to the current user. Returns all tags available in the project. Example output: Loading @@ -1614,8 +1666,10 @@ def tags(user: User) -> List[dict]: ] ``` """ project = Project.objects.filter(project_id).first() _check_project_permission(user, project, "tag.read") tags_list = [] for tag_instance in Tag.objects.filter(owner=user): for tag_instance in Tag.objects.filter(project=project): tags_list.append(serializers.tag(tag_instance)) return tags_list Loading @@ -1629,9 +1683,11 @@ def add_tag_to_collection(user: User, tag_uid: str, collection_id: int) -> bool: """ try: collection_instance = Collection.objects.get( owner=user, id=collection_id, deleted_at__isnull=True pk=collection_id, deleted_at__isnull=True ) tag_instance = Tag.objects.get(owner=user, uid=tag_uid) project = collection_instance.project _check_project_permission(user, project, "collection.write") tag_instance = Tag.objects.get(project=project, uid=tag_uid) collection_instance.tags.add(tag_instance) return True except ( Loading @@ -1652,9 +1708,11 @@ def remove_tag_from_collection(user: User, tag_uid: str, collection_id: int) -> """ try: collection_instance = Collection.objects.get( owner=user, id=collection_id, deleted_at__isnull=True pk=collection_id, deleted_at__isnull=True ) tag_instance = Tag.objects.get(owner=user, uid=tag_uid) project = collection_instance.project _check_project_permission(user, project, "collection.write") tag_instance = Tag.objects.get(project=project, uid=tag_uid) collection_instance.tags.remove(tag_instance) return True except ( Loading @@ -1675,9 +1733,11 @@ def add_tag_to_resource(user: User, tag_uid: str, resource_id: int) -> bool: """ try: resource_instance = Resource.objects.get( ptr_owner=user, id=resource_id, deleted_at__isnull=True id=resource_id, deleted_at__isnull=True ) tag_instance = Tag.objects.get(owner=user, uid=tag_uid) project = resource_instance.ptr_project _check_project_permission(user, project, "resource.write") tag_instance = Tag.objects.get(project=project, uid=tag_uid) resource_instance.tags.add(tag_instance) return True except ( Loading @@ -1698,9 +1758,11 @@ def remove_tag_from_resource(user: User, tag_uid: str, resource_id: int) -> bool """ try: resource_instance = Resource.objects.get( ptr_owner=user, id=resource_id, deleted_at__isnull=True id=resource_id, deleted_at__isnull=True ) tag_instance = Tag.objects.get(owner=user, uid=tag_uid) project = resource_instance.ptr_project _check_project_permission(user, project, "resource.write") tag_instance = Tag.objects.get(project=project, uid=tag_uid) resource_instance.tags.remove(tag_instance) return True except ( Loading Loading @@ -1781,18 +1843,22 @@ def set_representative_resource( """ try: collection_instance = Collection.objects.get( pk=collection_id, owner=user, deleted_at__isnull=True pk=collection_id, deleted_at__isnull=True ) if not resource_id: collection_instance.representative = None collection_instance.save() return True resource_instance = Resource.objects.get( pk=resource_id, ptr_owner=user, deleted_at__isnull=True pk=resource_id, deleted_at__isnull=True ) _check_project_permission(user, collection_instance.project, "collection.write") _check_project_permission(user, resource_instance.ptr_project, "resource.read") if resource_instance.ptr_project_id == collection_instance.project_id: collection_instance.representative = resource_instance collection_instance.save() return True return False except (Collection.DoesNotExist, Resource.DoesNotExist): return False Loading @@ -1818,18 +1884,21 @@ def replace_file(user: User, from_resource_id: int, to_resource_id: int) -> bool """ try: from_resource_instance = Resource.objects.get( ptr_owner=user, pk=from_resource_id, deleted_at__isnull=True pk=from_resource_id, deleted_at__isnull=True ) if not from_resource_instance.file: return False to_resource_instance = Resource.objects.get( ptr_owner=user, pk=to_resource_id, deleted_at__isnull=True pk=to_resource_id, deleted_at__isnull=True ) if not to_resource_instance.file: return False _check_project_permission( user, from_resource_instance.ptr_project, "resource.read" ) _check_project_permission( user, to_resource_instance.ptr_project, "resource.write" ) try: exif_set = MetadataSet.objects.get(title="ExifTool") # remove to_resource exif metas Loading Loading @@ -1872,7 +1941,8 @@ def set_is_oai_record( will be used in OAI-PMH requests. """ try: collection_instance = Collection.objects.get(pk=collection_id, owner=user) collection_instance = Collection.objects.get(pk=collection_id) _check_project_permission(user, collection_instance.project, "collection.write") collection_instance.is_oai_record = is_oai_record # TODO: fetch and save ARK identifier collection_instance.save() Loading