Loading resources/helpers.py +7 −7 Original line number Diff line number Diff line Loading @@ -157,9 +157,9 @@ def make_iiif(f: models.File): def delete_exif_metas(f: models.File) -> int: deleted_counter = 0 public_owner = User.objects.get(username="public_user") public_project = models.fetch_public_project() exiftools_metas_set = models.MetadataSet.objects.filter( title="ExifTool", owner=public_owner title="ExifTool", project=public_project ).first() for meta_value in models.MetadataResourceValue.objects.filter( resource=f, metadata__set=exiftools_metas_set Loading @@ -173,23 +173,23 @@ def set_exif_metas(f: models.File) -> int: """ Will run Exiftool on given models.File.local_path(). Extracted data is then converted to Metadatas. ExifTool MetadataSet and Metadatas alway have public_owner as owner. ExifTool MetadataSet and Metadatas always have public_project as project. """ added_counter = 0 public_owner = User.objects.get(username="public_user") public_project = models.fetch_public_project() exiftools_metas = image_metadatas(f.local_path()) if "ExifTool:Error" not in exiftools_metas: # first delete ExifTool metas delete_exif_metas(f) # then insert new metas from extracted data exiftools_metas_set = models.MetadataSet.objects.filter( title="ExifTool", owner=public_owner title="ExifTool", project=public_project ).first() if exiftools_metas_set: for key in exiftools_metas: metadata, created = models.Metadata.objects.get_or_create( title=key, set=exiftools_metas_set, owner=public_owner title=key, set=exiftools_metas_set, project=public_project ) models.MetadataResourceValue.objects.get_or_create( metadata=metadata, Loading resources/migrations/0014_auto_20210915_2024.py +18 −1 Original line number Diff line number Diff line Loading @@ -11,7 +11,7 @@ from resources.models import Project, Role, ProjectAccess, Permission def migrate_property(): permission_instances = [] obj_types = ["collection", "resource", "metadata", "metadataset", "file", "tag"] permissions = ["read", "write", "delete"] permissions = ["add", "read", "write", "delete"] for obj_type in obj_types: for permission in permissions: perm, created = Permission.objects.get_or_create( Loading Loading @@ -61,6 +61,23 @@ def migrate_property(): project.pk, user.pk ) ) # allow read access to public_project for all users # (ie. allow access to exif and OCR metas) public_user = User.objects.get(username="public_user") public_project = Project.objects.get(projectaccess__user=public_user) public_read_role, created = Role.objects.get_or_create( label="public_reader", project=public_project ) for permission_label in [ "collection.read", "resource.read", "metadata.read", "metadataset.read", "file.read", "tag.read", ]: permission = Permission.objects.get(label=permission_label) public_read_role.permissions.add(permission) class Migration(migrations.Migration): Loading resources/models.py +15 −11 Original line number Diff line number Diff line Loading @@ -10,6 +10,7 @@ from typing import Iterator, Union, List from django.db.models.signals import post_save from django.dispatch import receiver from subprocess import call from functools import lru_cache def hash_to_iiif_path(file_hash: str) -> str: Loading Loading @@ -61,9 +62,12 @@ class Project(models.Model): return self.label @lru_cache() def fetch_public_project() -> Project: project, created = Project.objects.get_or_create(label="public project") return project public_owner = User.objects.get(username="public_user") # there should be one public project after migrations public_project = Project.objects.filter(projectaccess__user=public_owner).first() return public_project class Tag(models.Model): Loading Loading @@ -271,12 +275,12 @@ class File(Resource): """ Fetch OCR output if available. None if not available. """ public_owner = User.objects.get(username="public_user") public_project = fetch_public_project() metas_set, created = MetadataSet.objects.get_or_create( title="OCR", owner=public_owner title="OCR", project=public_project ) meta, created = Metadata.objects.get_or_create( owner=public_owner, title="tesseract output", set=metas_set title="tesseract output", set=metas_set, project=public_project ) try: meta_value = MetadataResourceValue.objects.get(metadata=meta, resource=self) Loading @@ -299,12 +303,12 @@ class File(Resource): if ocr_return_code == 0: with open(self.local_path() + ".ocr.txt", "r") as ocr: content = ocr.read() public_owner = User.objects.get(username="public_user") public_project = fetch_public_project() metas_set, created = MetadataSet.objects.get_or_create( title="OCR", owner=public_owner title="OCR", project=public_project ) meta, created = Metadata.objects.get_or_create( owner=public_owner, title="tesseract output", set=metas_set project=public_project, title="tesseract output", set=metas_set ) (_, created,) = MetadataResourceValue.objects.get_or_create( metadata=meta, resource=self, value=content.strip() Loading @@ -317,12 +321,12 @@ class File(Resource): if pdftotext_return_code == 0: with open(self.local_path() + ".pdftotext.txt", "r") as text_layer: content = text_layer.read() public_owner = User.objects.get(username="public_user") public_project = fetch_public_project() metas_set, created = MetadataSet.objects.get_or_create( title="OCR", owner=public_owner title="OCR", project=public_project ) meta, created = Metadata.objects.get_or_create( owner=public_owner, title="pdftotext output", set=metas_set project=public_project, title="pdftotext output", set=metas_set ) (_, created,) = MetadataResourceValue.objects.get_or_create( metadata=meta, resource=self, value=content.strip() Loading rpc/methods.py +57 −24 Original line number Diff line number Diff line Loading @@ -12,6 +12,7 @@ from resources.models import ( Project, ProjectAccess, APIKey, fetch_public_project, ) from django.contrib.auth.models import User from django.db.models import QuerySet Loading @@ -28,10 +29,19 @@ class ServiceException(Exception): pass def _check_project_permission(user: User, project: Project, permission: str) -> bool: def _check_project_permission( user: User, project: Union[Project, int], permission: str ) -> bool: """ Will raise a ServiceException if user has no access to given project/permission. Will raise a ServiceException if: - user has no access to given project/permission - project is int and no such pk exists """ if isinstance(project, int): try: project = Project.objects.get(pk=project) except Project.DoesNotExist: raise ServiceException("no such project") access = ProjectAccess.objects.filter( user=user, project=project, role__permissions__label=permission ).first() Loading Loading @@ -88,9 +98,11 @@ def projects_permissions(user: User) -> List[Dict]: projects_permissions.rpc_groups = ["Utilities"] def metadatasets(user: User) -> List[Dict]: def metadatasets(user: User, project_id: int) -> List[Dict]: """ Get the list of all the user's metadata sets. Get the list of all the user's metadata sets. This includes metadatas sets for the given project_id, as well as the "public" metadatas sets (exiftool, ocr, etc). For each metadatas set, the number of metadatas is given in metas_count Example output: Loading @@ -102,14 +114,19 @@ def metadatasets(user: User) -> List[Dict]: ] ``` """ try: project = Project.objects.get(pk=project_id) _check_project_permission(user, project, "metadataset.read") data = [] public_owner = User.objects.get(username="public_user") # Get the project metadatasets AND the public metadatasets query_set: Iterator[MetadataSet] = MetadataSet.objects.filter( owner=user ) | MetadataSet.objects.filter(owner=public_owner) project=project ) | MetadataSet.objects.filter(project=fetch_public_project()) for item in query_set: data.append(serializers.metadataset(item)) return data except Project.DoesNotExist: raise ServiceException("no such project") metadatasets.rpc_groups = ["Metadatas"] Loading Loading @@ -145,10 +162,9 @@ def metadatas(user: User, metadata_set_id: int) -> List[Dict]: ``` """ data = [] public_owner = User.objects.get(username="public_user") query_set: Union[Iterator[MetadataSet], QuerySet] = MetadataSet.objects.filter( owner=user, id=metadata_set_id ) | MetadataSet.objects.filter(owner=public_owner, id=metadata_set_id) project__projectaccess__user=user, id=metadata_set_id ) | MetadataSet.objects.filter(project=fetch_public_project(), id=metadata_set_id) metadata_set: MetadataSet = query_set.first() if metadata_set: for metadata_instance in Metadata.objects.filter( Loading Loading @@ -178,10 +194,11 @@ def metadata(user: User, metadata_id: int) -> Union[Dict, None]: } ``` """ public_owner = User.objects.get(username="public_user") query_set: Union[Iterator[Collection], QuerySet] = Metadata.objects.filter( pk=metadata_id, owner=user ) | Metadata.objects.filter(pk=metadata_id, owner=public_owner) pk=metadata_id, project__projectaccess__user=user, project__projectaccess__role__permissions__label="metadata.read", ) metadata_instance = query_set.first() if not metadata_instance: return None Loading Loading @@ -1088,11 +1105,20 @@ def add_meta_to_resource( if meta_value == "" or meta_value is None: return False try: public_owner = User.objects.get(username="public_user") resource_instance = Resource.objects.get( ptr_owner=user, id=resource_id, deleted_at__isnull=True pk=resource_id, deleted_at__isnull=True, ptr_project__projectaccess__user=user, ptr_project__projectaccess__role__permission__label="resource.read", ) # Adding a meta value to a resource is a resource.write, NOT a metadata.write. # No need to go further. _check_project_permission(user, resource_instance.ptr_project, "resource.write") meta = Metadata.objects.get( pk=meta_id, project__projectaccess__user=user, project__projectaccess__role__permission__label="metadata.read", ) meta = Metadata.objects.get(owner__in=[public_owner, user], id=meta_id) meta_value_instance, created = MetadataResourceValue.objects.get_or_create( metadata=meta, resource=resource_instance, value=meta_value ) Loading Loading @@ -1140,11 +1166,18 @@ def add_meta_to_collection( if meta_value == "" or meta_value is None: return False try: public_owner = User.objects.get(username="public_user") collection_instance = Collection.objects.get( owner=user, id=collection_id, deleted_at__isnull=True pk=collection_id, deleted_at__isnull=True, project__projectaccess__user=user, project__projectaccess__role__permission__label="collection.read", ) meta = Metadata.objects.get( id=meta_id, project__projectaccess__user=user, project__projectaccess__role__permission__label="metadata.read", ) meta = Metadata.objects.get(owner__in=[public_owner, user], id=meta_id) _check_project_permission(user, collection_instance.project, "collection.write") meta_value_instance, created = MetadataCollectionValue.objects.get_or_create( metadata=meta, collection=collection_instance, value=meta_value ) Loading Loading
resources/helpers.py +7 −7 Original line number Diff line number Diff line Loading @@ -157,9 +157,9 @@ def make_iiif(f: models.File): def delete_exif_metas(f: models.File) -> int: deleted_counter = 0 public_owner = User.objects.get(username="public_user") public_project = models.fetch_public_project() exiftools_metas_set = models.MetadataSet.objects.filter( title="ExifTool", owner=public_owner title="ExifTool", project=public_project ).first() for meta_value in models.MetadataResourceValue.objects.filter( resource=f, metadata__set=exiftools_metas_set Loading @@ -173,23 +173,23 @@ def set_exif_metas(f: models.File) -> int: """ Will run Exiftool on given models.File.local_path(). Extracted data is then converted to Metadatas. ExifTool MetadataSet and Metadatas alway have public_owner as owner. ExifTool MetadataSet and Metadatas always have public_project as project. """ added_counter = 0 public_owner = User.objects.get(username="public_user") public_project = models.fetch_public_project() exiftools_metas = image_metadatas(f.local_path()) if "ExifTool:Error" not in exiftools_metas: # first delete ExifTool metas delete_exif_metas(f) # then insert new metas from extracted data exiftools_metas_set = models.MetadataSet.objects.filter( title="ExifTool", owner=public_owner title="ExifTool", project=public_project ).first() if exiftools_metas_set: for key in exiftools_metas: metadata, created = models.Metadata.objects.get_or_create( title=key, set=exiftools_metas_set, owner=public_owner title=key, set=exiftools_metas_set, project=public_project ) models.MetadataResourceValue.objects.get_or_create( metadata=metadata, Loading
resources/migrations/0014_auto_20210915_2024.py +18 −1 Original line number Diff line number Diff line Loading @@ -11,7 +11,7 @@ from resources.models import Project, Role, ProjectAccess, Permission def migrate_property(): permission_instances = [] obj_types = ["collection", "resource", "metadata", "metadataset", "file", "tag"] permissions = ["read", "write", "delete"] permissions = ["add", "read", "write", "delete"] for obj_type in obj_types: for permission in permissions: perm, created = Permission.objects.get_or_create( Loading Loading @@ -61,6 +61,23 @@ def migrate_property(): project.pk, user.pk ) ) # allow read access to public_project for all users # (ie. allow access to exif and OCR metas) public_user = User.objects.get(username="public_user") public_project = Project.objects.get(projectaccess__user=public_user) public_read_role, created = Role.objects.get_or_create( label="public_reader", project=public_project ) for permission_label in [ "collection.read", "resource.read", "metadata.read", "metadataset.read", "file.read", "tag.read", ]: permission = Permission.objects.get(label=permission_label) public_read_role.permissions.add(permission) class Migration(migrations.Migration): Loading
resources/models.py +15 −11 Original line number Diff line number Diff line Loading @@ -10,6 +10,7 @@ from typing import Iterator, Union, List from django.db.models.signals import post_save from django.dispatch import receiver from subprocess import call from functools import lru_cache def hash_to_iiif_path(file_hash: str) -> str: Loading Loading @@ -61,9 +62,12 @@ class Project(models.Model): return self.label @lru_cache() def fetch_public_project() -> Project: project, created = Project.objects.get_or_create(label="public project") return project public_owner = User.objects.get(username="public_user") # there should be one public project after migrations public_project = Project.objects.filter(projectaccess__user=public_owner).first() return public_project class Tag(models.Model): Loading Loading @@ -271,12 +275,12 @@ class File(Resource): """ Fetch OCR output if available. None if not available. """ public_owner = User.objects.get(username="public_user") public_project = fetch_public_project() metas_set, created = MetadataSet.objects.get_or_create( title="OCR", owner=public_owner title="OCR", project=public_project ) meta, created = Metadata.objects.get_or_create( owner=public_owner, title="tesseract output", set=metas_set title="tesseract output", set=metas_set, project=public_project ) try: meta_value = MetadataResourceValue.objects.get(metadata=meta, resource=self) Loading @@ -299,12 +303,12 @@ class File(Resource): if ocr_return_code == 0: with open(self.local_path() + ".ocr.txt", "r") as ocr: content = ocr.read() public_owner = User.objects.get(username="public_user") public_project = fetch_public_project() metas_set, created = MetadataSet.objects.get_or_create( title="OCR", owner=public_owner title="OCR", project=public_project ) meta, created = Metadata.objects.get_or_create( owner=public_owner, title="tesseract output", set=metas_set project=public_project, title="tesseract output", set=metas_set ) (_, created,) = MetadataResourceValue.objects.get_or_create( metadata=meta, resource=self, value=content.strip() Loading @@ -317,12 +321,12 @@ class File(Resource): if pdftotext_return_code == 0: with open(self.local_path() + ".pdftotext.txt", "r") as text_layer: content = text_layer.read() public_owner = User.objects.get(username="public_user") public_project = fetch_public_project() metas_set, created = MetadataSet.objects.get_or_create( title="OCR", owner=public_owner title="OCR", project=public_project ) meta, created = Metadata.objects.get_or_create( owner=public_owner, title="pdftotext output", set=metas_set project=public_project, title="pdftotext output", set=metas_set ) (_, created,) = MetadataResourceValue.objects.get_or_create( metadata=meta, resource=self, value=content.strip() Loading
rpc/methods.py +57 −24 Original line number Diff line number Diff line Loading @@ -12,6 +12,7 @@ from resources.models import ( Project, ProjectAccess, APIKey, fetch_public_project, ) from django.contrib.auth.models import User from django.db.models import QuerySet Loading @@ -28,10 +29,19 @@ class ServiceException(Exception): pass def _check_project_permission(user: User, project: Project, permission: str) -> bool: def _check_project_permission( user: User, project: Union[Project, int], permission: str ) -> bool: """ Will raise a ServiceException if user has no access to given project/permission. Will raise a ServiceException if: - user has no access to given project/permission - project is int and no such pk exists """ if isinstance(project, int): try: project = Project.objects.get(pk=project) except Project.DoesNotExist: raise ServiceException("no such project") access = ProjectAccess.objects.filter( user=user, project=project, role__permissions__label=permission ).first() Loading Loading @@ -88,9 +98,11 @@ def projects_permissions(user: User) -> List[Dict]: projects_permissions.rpc_groups = ["Utilities"] def metadatasets(user: User) -> List[Dict]: def metadatasets(user: User, project_id: int) -> List[Dict]: """ Get the list of all the user's metadata sets. Get the list of all the user's metadata sets. This includes metadatas sets for the given project_id, as well as the "public" metadatas sets (exiftool, ocr, etc). For each metadatas set, the number of metadatas is given in metas_count Example output: Loading @@ -102,14 +114,19 @@ def metadatasets(user: User) -> List[Dict]: ] ``` """ try: project = Project.objects.get(pk=project_id) _check_project_permission(user, project, "metadataset.read") data = [] public_owner = User.objects.get(username="public_user") # Get the project metadatasets AND the public metadatasets query_set: Iterator[MetadataSet] = MetadataSet.objects.filter( owner=user ) | MetadataSet.objects.filter(owner=public_owner) project=project ) | MetadataSet.objects.filter(project=fetch_public_project()) for item in query_set: data.append(serializers.metadataset(item)) return data except Project.DoesNotExist: raise ServiceException("no such project") metadatasets.rpc_groups = ["Metadatas"] Loading Loading @@ -145,10 +162,9 @@ def metadatas(user: User, metadata_set_id: int) -> List[Dict]: ``` """ data = [] public_owner = User.objects.get(username="public_user") query_set: Union[Iterator[MetadataSet], QuerySet] = MetadataSet.objects.filter( owner=user, id=metadata_set_id ) | MetadataSet.objects.filter(owner=public_owner, id=metadata_set_id) project__projectaccess__user=user, id=metadata_set_id ) | MetadataSet.objects.filter(project=fetch_public_project(), id=metadata_set_id) metadata_set: MetadataSet = query_set.first() if metadata_set: for metadata_instance in Metadata.objects.filter( Loading Loading @@ -178,10 +194,11 @@ def metadata(user: User, metadata_id: int) -> Union[Dict, None]: } ``` """ public_owner = User.objects.get(username="public_user") query_set: Union[Iterator[Collection], QuerySet] = Metadata.objects.filter( pk=metadata_id, owner=user ) | Metadata.objects.filter(pk=metadata_id, owner=public_owner) pk=metadata_id, project__projectaccess__user=user, project__projectaccess__role__permissions__label="metadata.read", ) metadata_instance = query_set.first() if not metadata_instance: return None Loading Loading @@ -1088,11 +1105,20 @@ def add_meta_to_resource( if meta_value == "" or meta_value is None: return False try: public_owner = User.objects.get(username="public_user") resource_instance = Resource.objects.get( ptr_owner=user, id=resource_id, deleted_at__isnull=True pk=resource_id, deleted_at__isnull=True, ptr_project__projectaccess__user=user, ptr_project__projectaccess__role__permission__label="resource.read", ) # Adding a meta value to a resource is a resource.write, NOT a metadata.write. # No need to go further. _check_project_permission(user, resource_instance.ptr_project, "resource.write") meta = Metadata.objects.get( pk=meta_id, project__projectaccess__user=user, project__projectaccess__role__permission__label="metadata.read", ) meta = Metadata.objects.get(owner__in=[public_owner, user], id=meta_id) meta_value_instance, created = MetadataResourceValue.objects.get_or_create( metadata=meta, resource=resource_instance, value=meta_value ) Loading Loading @@ -1140,11 +1166,18 @@ def add_meta_to_collection( if meta_value == "" or meta_value is None: return False try: public_owner = User.objects.get(username="public_user") collection_instance = Collection.objects.get( owner=user, id=collection_id, deleted_at__isnull=True pk=collection_id, deleted_at__isnull=True, project__projectaccess__user=user, project__projectaccess__role__permission__label="collection.read", ) meta = Metadata.objects.get( id=meta_id, project__projectaccess__user=user, project__projectaccess__role__permission__label="metadata.read", ) meta = Metadata.objects.get(owner__in=[public_owner, user], id=meta_id) _check_project_permission(user, collection_instance.project, "collection.write") meta_value_instance, created = MetadataCollectionValue.objects.get_or_create( metadata=meta, collection=collection_instance, value=meta_value ) Loading