Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
permission: refactoring document permission factory
Browse files Browse the repository at this point in the history
This commit create a specific permission class about document resource.
This class centralizes all permissions related to document resources.

Co-Authored-by: Renaud Michotte <renaud.michotte@gmail.com>
zannkukai committed Jul 21, 2020
1 parent cdf6c67 commit 25e52ed
Showing 5 changed files with 193 additions and 16 deletions.
15 changes: 11 additions & 4 deletions rero_ils/config.py
Original file line number Diff line number Diff line change
@@ -50,6 +50,7 @@
from .modules.circ_policies.api import CircPolicy
from .modules.circ_policies.permissions import can_update_circ_policy_factory
from .modules.documents.api import Document
from .modules.documents.permissions import DocumentPermission
from .modules.holdings.api import Holding
from .modules.item_types.api import ItemType
from .modules.items.api import Item
@@ -448,10 +449,16 @@ def _(x):
default_media_type='application/json',
max_result_window=5000000,
search_factory_imp='rero_ils.query:view_search_factory',
read_permission_factory_imp=allow_all,
list_permission_factory_imp=allow_all,
update_permission_factory_imp=librarian_update_permission_factory,
delete_permission_factory_imp=librarian_update_permission_factory
list_permission_factory_imp=lambda record: record_permission_factory(
action='list', record=record, cls=DocumentPermission),
read_permission_factory_imp=lambda record: record_permission_factory(
action='read', record=record, cls=DocumentPermission),
create_permission_factory_imp=lambda record: record_permission_factory(
action='create', record=record, cls=DocumentPermission),
update_permission_factory_imp=lambda record: record_permission_factory(
action='update', record=record, cls=DocumentPermission),
delete_permission_factory_imp=lambda record: record_permission_factory(
action='delete', record=record, cls=DocumentPermission),
),
item=dict(
pid_type='item',
86 changes: 86 additions & 0 deletions rero_ils/modules/documents/permissions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# -*- coding: utf-8 -*-
#
# RERO ILS
# Copyright (C) 2020 RERO
# Copyright (C) 2020 UCLouvain
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, version 3 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

"""Permissions for documents."""

from rero_ils.modules.patrons.api import current_patron
from rero_ils.modules.permissions import RecordPermission


class DocumentPermission(RecordPermission):
"""Document permissions."""

@classmethod
def list(cls, user, record=None):
"""List permission check.
:param user: Logged user.
:param record: Record to check.
:return: True is action can be done.
"""
# everyone can list document
return True

@classmethod
def read(cls, user, record):
"""Read permission check.
:param user: Logged user.
:param record: Record to check.
:return: True is action can be done.
"""
# same as list permission
return cls.list(user, record)

@classmethod
def create(cls, user, record=None):
"""Create permission check.
:param user: Logged user.
:param record: Record to check.
:return: True is action can be done.
"""
# user should be authenticated
if not current_patron:
return False
# only staff members (lib, sys_lib) are allowed to create any documents
return current_patron.is_librarian

@classmethod
def update(cls, user, record):
"""Update permission check.
:param user: Logged user.
:param record: Record to check.
:return: True is action can be done.
"""
# basically same than create except if document cannot be edited
if record and record.can_edit:
return cls.create(user, record)
return False

@classmethod
def delete(cls, user, record):
"""Delete permission check.
:param user: Logged user.
:param record: Record to check.
:return: True if action can be done.
"""
# same as update
return cls.update(user, record)
12 changes: 0 additions & 12 deletions rero_ils/permissions.py
Original file line number Diff line number Diff line change
@@ -208,23 +208,11 @@ def can_access_item(user=None, item=None):
return False


def can_edit(user=None):
"""User has editor role."""
return user_is_authenticated() and librarian_permission.can()


def librarian_permission_factory(record, *args, **kwargs):
"""User has editor role."""
return librarian_permission


def librarian_update_permission_factory(record, *args, **kwargs):
"""User has editor role and the record is editable."""
if record.can_edit:
return librarian_permission
return type('Check', (), {'can': lambda x: False})()


def librarian_delete_permission_factory(
record, credentials_only=False, *args, **kwargs):
"""User can delete record."""
96 changes: 96 additions & 0 deletions tests/api/documents/test_documents_permissions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# -*- coding: utf-8 -*-
#
# RERO ILS
# Copyright (C) 2020 RERO
# Copyright (C) 2020 UCLouvain
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, version 3 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

import mock
from flask import url_for
from invenio_accounts.testutils import login_user_via_session
from utils import get_json

from rero_ils.modules.documents.permissions import DocumentPermission


def test_documents_permissions_api(client, document, ebook_1,
system_librarian_martigny_no_email):
"""Test documents permissions api."""
# Logged as system librarian.
# * All operation are allowed for normal document
# * Even a harvested document cannot be delete/edit
doc_permission_url = url_for(
'api_blueprint.permissions',
route_name='documents',
record_pid=document.pid
)
login_user_via_session(client, system_librarian_martigny_no_email.user)
res = client.get(doc_permission_url)
assert res.status_code == 200
data = get_json(res)
assert data['read']['can']
assert data['list']['can']
assert data['create']['can']
assert data['update']['can']
assert data['delete']['can']

doc_permission_url = url_for(
'api_blueprint.permissions',
route_name='documents',
record_pid=ebook_1.pid
)
login_user_via_session(client, system_librarian_martigny_no_email.user)
res = client.get(doc_permission_url)
assert res.status_code == 200
data = get_json(res)
assert data['read']['can']
assert data['list']['can']
assert data['create']['can']
assert not data['update']['can']
assert not data['delete']['can']


def test_documents_permissions(patron_martigny_no_email,
librarian_martigny_no_email,
document):
"""Test documents permissions class."""

# Anonymous user
assert DocumentPermission.list(None, document)
assert DocumentPermission.read(None, document)
assert not DocumentPermission.create(None, document)
assert not DocumentPermission.update(None, document)
assert not DocumentPermission.delete(None, document)

# As Patron
with mock.patch(
'rero_ils.modules.documents.permissions.current_patron',
patron_martigny_no_email
):
assert DocumentPermission.list(None, document)
assert DocumentPermission.read(None, document)
assert not DocumentPermission.create(None, document)
assert not DocumentPermission.update(None, document)
assert not DocumentPermission.delete(None, document)

# As Librarian
with mock.patch(
'rero_ils.modules.documents.permissions.current_patron',
librarian_martigny_no_email
):
assert DocumentPermission.list(None, document)
assert DocumentPermission.read(None, document)
assert DocumentPermission.create(None, document)
assert DocumentPermission.update(None, document)
assert DocumentPermission.delete(None, document)
File renamed without changes.

0 comments on commit 25e52ed

Please sign in to comment.