Skip to content

Commit

Permalink
has_permission check for link creation and class for combining multip… (
Browse files Browse the repository at this point in the history
#227)

* has_permission check for link creation and class for combining multiple conditions

* has published record

* has published record cjecl

* allowing use of limited set of links for search results

* links template class comes from service config

* deprecated calling link condtions from .records

* moved link conditions to services.config
using & and | model of combining

* file_service for file_record_class getter

* list_files in presets

* format

* version bump

* format and exception checking

* type checking and correct exception message

* Version bump

---------

Co-authored-by: Ronald Krist <[email protected]>
Co-authored-by: Mirek Simek <[email protected]>
  • Loading branch information
3 people authored Dec 4, 2024
1 parent 608713f commit 69fc7a5
Show file tree
Hide file tree
Showing 7 changed files with 162 additions and 17 deletions.
4 changes: 3 additions & 1 deletion oarepo_runtime/datastreams/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ def get_record_service_for_record_deprecated(record):
if service_record == type(record):
return svc


def get_file_service_for_record_class(record_class):
if not record_class:
return None
Expand All @@ -60,6 +59,9 @@ def get_file_service_for_record_class(record_class):
continue
return svc

def get_file_service_for_file_record_class(file_record_class):
record_class = file_record_class.record_cls
return get_file_service_for_record_class(record_class)

def get_file_service_for_record_service(
record_service, check_draft_files=True, record=None
Expand Down
46 changes: 33 additions & 13 deletions oarepo_runtime/records/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from typing import Type

from deprecated import deprecated
from invenio_records_resources.records import Record


Expand All @@ -11,20 +12,39 @@ def select_record_for_update(record_cls: Type[Record], persistent_identifier):
return record_cls(obj.data, model=obj)


def is_published_record(record, ctx):
"""Shortcut for links to determine if record is a published record."""
return not getattr(record, "is_draft", False)
@deprecated("Moved to oarepo_runtime.services.config.link_conditions")
def is_published_record_function():
"""Shortcut for links to determine if record is a published.
This function is deprecated. Use oarepo_runtime.services.config.is_published_record instead.
"""
from oarepo_runtime.services.config.link_conditions import is_published_record

def is_draft_record(record, ctx):
"""Shortcut for links to determine if record is a draft record."""
return getattr(record, "is_draft", False)
return is_published_record()


def has_draft(record, ctx):
"""Shortcut for links to determine if record is either a draft or a published one with a draft associated."""
if getattr(record, "is_draft", False):
return True
if getattr(record, "has_draft", False):
return True
return False
@deprecated("Moved to oarepo_runtime.services.config.link_conditions")
def is_draft_record_function():
"""Shortcut for links to determine if record is a draft record.
This function is deprecated. Use oarepo_runtime.services.config.is_draft_record instead.
"""
from oarepo_runtime.services.config.link_conditions import is_draft_record

return is_draft_record()


@deprecated("Moved to oarepo_runtime.services.config.link_conditions")
def has_draft_function():
"""Shortcut for links to determine if record is either a draft or a published one with a draft associated.
This function is deprecated. Use oarepo_runtime.services.config.has_draft instead.
"""
from oarepo_runtime.services.config.link_conditions import has_draft

return has_draft()


is_published_record = is_published_record_function()
is_draft = is_draft_record_function()
has_draft = has_draft_function()
14 changes: 14 additions & 0 deletions oarepo_runtime/services/config/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
from .link_conditions import (
has_draft,
has_permission,
has_permission_file_service,
has_published_record,
is_draft_record,
is_published_record,
)
from .permissions_presets import (
AuthenticatedPermissionPolicy,
EveryonePermissionPolicy,
Expand All @@ -12,4 +20,10 @@
"ReadOnlyPermissionPolicy",
"EveryonePermissionPolicy",
"AuthenticatedPermissionPolicy",
"is_published_record",
"is_draft_record",
"has_draft",
"has_permission",
"has_permission_file_service",
"has_published_record",
)
101 changes: 101 additions & 0 deletions oarepo_runtime/services/config/link_conditions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
from abc import abstractmethod

from invenio_pidstore.errors import PIDDoesNotExistError, PIDUnregistered
from invenio_records_resources.records.api import FileRecord
from invenio_records.api import RecordBase
from invenio_records_resources.records.api import Record
from logging import getLogger
from ...datastreams.utils import (
get_file_service_for_file_record_class,
get_file_service_for_record_class,
get_record_service_for_record,
)
log = getLogger(__name__)

class Condition:

@abstractmethod
def __call__(self, obj, ctx: dict):
raise NotImplementedError

def __and__(self, other):
return type(
"CompositeCondition",
(Condition,),
{"__call__": lambda _, obj, ctx: self(obj, ctx) and other(obj, ctx)},
)()

def __or__(self, other):
return type(
"CompositeCondition",
(Condition,),
{"__call__": lambda _, obj, ctx: self(obj, ctx) or other(obj, ctx)},
)()


class is_published_record(Condition):
"""Shortcut for links to determine if record is a published record."""

def __call__(self, obj: Record, ctx: dict):
return not getattr(obj, "is_draft", False)


class is_draft_record(Condition):
"""Shortcut for links to determine if record is a draft record."""

def __call__(self, obj: Record, ctx: dict):
return getattr(obj, "is_draft", False)


class has_draft(Condition):
"""Shortcut for links to determine if record is either a draft or a published one with a draft associated."""

def __call__(self, obj: Record, ctx: dict):
if getattr(obj, "is_draft", False):
return True
if getattr(obj, "has_draft", False):
return True
return False


class has_permission(Condition):
def __init__(self, action_name):
self.action_name = action_name

def __call__(self, obj: RecordBase, ctx: dict):
if isinstance(obj, FileRecord):
obj = obj.record
service = get_record_service_for_record(obj)
try:
return service.check_permission(
action_name=self.action_name, record=obj, **ctx
)
except Exception as e:
log.exception(f"Unexpected exception {e}.")



class has_permission_file_service(has_permission):

def __call__(self, obj: RecordBase, ctx: dict):
if isinstance(obj, FileRecord):
service = get_file_service_for_file_record_class(type(obj))
else:
service = get_file_service_for_record_class(type(obj))
try:
return service.check_permission(
action_name=self.action_name, record=obj, **ctx
)
except Exception as e:
log.exception(f"Unexpected exception {e}.")


class has_published_record(Condition):

def __call__(self, obj: Record, ctx: dict):
service = get_record_service_for_record(obj)
try:
service.record_cls.pid.resolve(obj["id"])
except (PIDUnregistered, PIDDoesNotExistError):
return False
return True
3 changes: 3 additions & 0 deletions oarepo_runtime/services/config/permissions_presets.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ class ReadOnlyPermissionPolicy(RecordPermissionPolicy):
can_read_files = [AnyUser(), SystemProcess()]
can_update_files = [SystemProcess()]
can_delete_files = [SystemProcess()]
can_list_files = [SystemProcess()]

can_edit = [SystemProcess()]
can_new_version = [SystemProcess()]
Expand Down Expand Up @@ -92,6 +93,7 @@ class EveryonePermissionPolicy(RecordPermissionPolicy):
can_read_files = [SystemProcess(), AnyUser()]
can_update_files = [SystemProcess(), AnyUser()]
can_delete_files = [SystemProcess(), AnyUser()]
can_list_files = [SystemProcess(), AnyUser()]

can_edit = [SystemProcess(), AnyUser()]
can_new_version = [SystemProcess(), AnyUser()]
Expand Down Expand Up @@ -128,6 +130,7 @@ class AuthenticatedPermissionPolicy(RecordPermissionPolicy):
can_read_files = [SystemProcess(), AnyUser()]
can_update_files = [SystemProcess(), AuthenticatedUser()]
can_delete_files = [SystemProcess(), AuthenticatedUser()]
can_list_files = [SystemProcess(), AuthenticatedUser()]

can_edit = [SystemProcess(), AuthenticatedUser()]
can_new_version = [SystemProcess(), AuthenticatedUser()]
Expand Down
9 changes: 7 additions & 2 deletions oarepo_runtime/services/results.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,15 +114,20 @@ def hits(self):
record=record,
),
)
if self._links_item_tpl:
if hasattr(self._service.config, "links_search_item"):
links_tpl = self._service.config.search_item_links_template(
self._service.config.links_search_item
)
projection["links"] = links_tpl.expand(self._identity, record)
elif self._links_item_tpl:
projection["links"] = self._links_item_tpl.expand(
self._identity, record
)
# todo optimization viz FieldsResolver
for c in self.components:
c.update_data(
identity=self._identity,
record=self._record,
record=record,
projection=projection,
expand=self._expand,
)
Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[metadata]
name = oarepo-runtime
version = 1.5.75
version = 1.5.76
description = A set of runtime extensions of Invenio repository
authors = Alzbeta Pokorna
readme = README.md
Expand Down

0 comments on commit 69fc7a5

Please sign in to comment.