Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce conditional DisableIf generator & read-only mode #86

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions invenio_records_permissions/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#
# Copyright (C) 2019-2020 CERN.
# Copyright (C) 2019-2020 Northwestern University.
# Copyright (C) 2022-2024 TU Wien.
#
# Invenio-Records-Permissions is free software; you can redistribute it
# and/or modify it under the terms of the MIT License; see LICENSE file for
Expand All @@ -13,3 +14,6 @@
"invenio_records_permissions.policies.RecordPermissionPolicy"
)
"""PermissionPolicy for records."""

RECORDS_PERMISSIONS_READ_ONLY = False
max-moser marked this conversation as resolved.
Show resolved Hide resolved
"""Condition to trigger the ``DisableIfReadOnly`` permission generator."""
25 changes: 24 additions & 1 deletion invenio_records_permissions/generators.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#
# Copyright (C) 2019-2023 CERN.
# Copyright (C) 2019-2020 Northwestern University.
# Copyright (C) 2022-2024 TU Wien.
#
# Invenio-Records-Permissions is free software; you can redistribute it
# and/or modify it under the terms of the MIT License; see LICENSE file for
Expand All @@ -23,6 +24,7 @@
superuser_access,
system_process,
)
from invenio_base.utils import obj_or_import_string
from invenio_search.engine import dsl


Expand Down Expand Up @@ -221,7 +223,7 @@ def query_filter(self, identity=None, **kwargs):
**{
"internal.access_levels.{}".format(access_level): {
"scheme": "person",
"id": id_need.value
"id": id_need.value,
# TODO: Implement other schemes
}
}
Expand Down Expand Up @@ -296,6 +298,11 @@ def excludes(self, record=None, **kwargs):
]
return set(chain.from_iterable(excludes))

def query_filter(self, **kwargs):
"""Create query filter based on the condition."""
record = kwargs.pop("record", None)
return self._make_query(self._generators(record, **kwargs)) or []

@staticmethod
def _make_query(generators, **kwargs):
"""Make a query for one set of generators."""
Expand All @@ -318,6 +325,22 @@ def _condition(self, **_):
return current_app.config.get(self.config_key) in self.accept_values


class DisableIfReadOnly(IfConfig):
"""Disable action for ALL users if the system is in read-only mode.

This generator uses the ``RECORDS_PERMISSIONS_READ_ONLY`` configuration item
to determine if the read-only mode is set.
"""

def __init__(self):
"""Initialize generator."""
super().__init__(
config_key="RECORDS_PERMISSIONS_READ_ONLY",
then_=[Disable()],
else_=[],
)


#
# | Meta Restricted | Files Restricted | Access Right | Result |
# |-----------------|------------------|--------------|--------|
Expand Down
12 changes: 9 additions & 3 deletions invenio_records_permissions/policies/records.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,13 @@
from werkzeug.utils import import_string

from ..errors import UnknownGeneratorError
from ..generators import AnyUser, AnyUserIfPublic, Disable, RecordOwners
from ..generators import (
AnyUser,
AnyUserIfPublic,
Disable,
DisableIfReadOnly,
RecordOwners,
)
from .base import BasePermissionPolicy


Expand Down Expand Up @@ -59,13 +65,13 @@ class RecordPermissionPolicy(BasePermissionPolicy):
# Read access given to everyone if public record/files and owners always.
can_read = [AnyUserIfPublic(), RecordOwners()]
# Update access given to record owners.
can_update = [RecordOwners()]
can_update = [RecordOwners(), DisableIfReadOnly()]
# Delete access given to superuser-access action only
# (superuser-access is added by default by base policy)
can_delete = []
# Associated files permissions (which are really bucket permissions)
can_read_files = [AnyUserIfPublic(), RecordOwners()]
can_update_files = [RecordOwners()]
can_update_files = [RecordOwners(), DisableIfReadOnly()]
can_read_deleted_files = []

def __init__(self, action, **over):
Expand Down
19 changes: 18 additions & 1 deletion tests/test_generators.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
#
# Copyright (C) 2019 CERN.
# Copyright (C) 2019 Northwestern University.
# Copyright (C) 2023 Graz University of Technology
# Copyright (C) 2023 Graz University of Technology.
# Copyright (C) 2024 TU Wien.
#
# Invenio-Records-Permissions is free software; you can redistribute it
# and/or modify it under the terms of the MIT License; see LICENSE file for
Expand All @@ -22,6 +23,7 @@
AuthenticatedUser,
ConditionalGenerator,
Disable,
DisableIfReadOnly,
Generator,
IfConfig,
RecordOwners,
Expand Down Expand Up @@ -266,3 +268,18 @@ def test_ifconfig(app, create_record):
UserNeed(2),
UserNeed(3),
}


def test_disable_if_read_only(app):
generator = DisableIfReadOnly()

# Normal operation
app.config["RECORDS_PERMISSIONS_READ_ONLY"] = False
assert generator.excludes(record=None) == set()
assert generator.query_filter(record=None) == []

# System is in read-only mode
app.config["RECORDS_PERMISSIONS_READ_ONLY"] = True
assert generator.excludes(record=None) == {any_user}
query_filter = generator.query_filter(record=None)
assert query_filter.to_dict() == {"match_none": {}}