diff --git a/rero_ils/modules/patrons/views.py b/rero_ils/modules/patrons/views.py index 3d79f29275..b58d833ca8 100644 --- a/rero_ils/modules/patrons/views.py +++ b/rero_ils/modules/patrons/views.py @@ -33,6 +33,7 @@ from flask_menu import register_menu from flask_security import utils as security_utils from invenio_i18n.ext import current_i18n +from invenio_oauth2server.decorators import require_api_auth from .api import Patron, PatronsSearch, current_librarian, current_patrons from .permissions import get_allowed_roles_management @@ -320,7 +321,7 @@ def patron_authenticate(): @api_blueprint.route('/info', methods=['GET']) -@check_logged_as_patron +@require_api_auth() def info(): """Get patron info.""" token_scopes = flask_request.oauth.access_token.scopes @@ -342,6 +343,7 @@ def get_institution_code(institution): :param institution: Institution object. :returns: Code for the institution. """ + # TODO: make this non rero specific using a configuration return institution['code'] if institution['code'] != 'nj' else 'rbnj' # Process for all patrons @@ -357,7 +359,7 @@ def get_institution_code(institution): data = {} # Barcode - if patron['patron'].get('barcode'): + if patron.get('patron', {}).get('barcode'): data['barcode'] = patron['patron']['barcode'][0] # Full name @@ -372,15 +374,21 @@ def get_institution_code(institution): if 'patron_types' in token_scopes: patron_types = [] for patron in patrons: - patron_types.append({ - 'patron_type': - patron['patron']['type']['code'], - 'institution': - get_institution_code(patron['institution']), - 'expiration_date': - datetime.datetime.strptime(patron['patron']['expiration_date'], - '%Y-%m-%d').isoformat() - }) - data['patron_types'] = patron_types + info = {} + patron_type_code = patron.get( + 'patron', {}).get('type', {}).get('code') + if patron_type_code: + info['patron_type'] = patron_type_code + if patron.get('institution'): + info['institution'] = get_institution_code( + patron['institution']) + if patron.get('patron', {}).get('expiration_date'): + info['expiration_date'] = datetime.datetime.strptime( + patron['patron']['expiration_date'], + '%Y-%m-%d').isoformat() + if info: + patron_types.append(info) + if patron_types: + data['patron_types'] = patron_types return jsonify(data) diff --git a/tests/api/patrons/test_patrons_rest.py b/tests/api/patrons/test_patrons_rest.py index bf9b55d0c4..71af09a88a 100644 --- a/tests/api/patrons/test_patrons_rest.py +++ b/tests/api/patrons/test_patrons_rest.py @@ -24,6 +24,8 @@ import mock from flask import url_for from invenio_accounts.testutils import login_user_via_session +from invenio_db import db +from invenio_oauth2server.models import Client, Token from utils import VerifyRecordPermissionPatch, create_patron, get_json, \ postdata, to_relative_url @@ -569,37 +571,68 @@ def test_patron_messages(client, patron_martigny): 'Will be back in february.' -def test_patron_info(client, patron_martigny, monkeypatch): +def test_patron_info(app, client, patron_martigny, librarian_martigny): """Test patron info.""" - class MockToken: - """Mock token class.""" - scopes = [] - - class MockOAuth: - """Mock OAuth class.""" - access_token = MockToken() + # All scopes + scopes = [ + 'fullname', 'birthdate', 'institution', 'expiration_date', + 'patron_type', 'patron_types' + ] - class MockRequest: - """Mock request class.""" - oauth = MockOAuth() + # create a oauth client liked to the librarian account + oauth_client = Client( + client_id='dev', + client_secret='dev', + name='Test name', + description='Test description', + is_confidential=False, + user=librarian_martigny.user, + website='http://foo.org', + _redirect_uris='') + + # token with all scopes + token = Token( + client=oauth_client, + user=patron_martigny.user, + token_type='bearer', + access_token='test_access_1', + expires=None, + is_personal=False, + is_internal=False, + _scopes=' '.join(scopes)) + + # token without scope + no_scope_token = Token( + client=oauth_client, + user=patron_martigny.user, + token_type='bearer', + access_token='test_access_2', + expires=None, + is_personal=False, + is_internal=False) + + db.session.add(oauth_client) + db.session.add(token) + db.session.commit() + + # denied with a wrong token + res = client.get(url_for('api_patrons.info', access_token='wrong')) + assert res.status_code == 401 - monkeypatch.setattr('rero_ils.modules.patrons.views.flask_request', - MockRequest) - login_user_via_session(client, patron_martigny.user) - url = url_for('api_patrons.info') + # denied without token + res = client.get(url_for('api_patrons.info')) + assert res.status_code == 401 - # No scope - res = client.get(url) + # minimal information without scope + res = client.get( + url_for('api_patrons.info', access_token=no_scope_token.access_token)) assert res.status_code == 200 - assert res.json == {'barcode': '4098124352'} + assert res.json == {'barcode': patron_martigny['patron']['barcode'].pop()} - # All scopes - MockToken.scopes = [ - 'fullname', 'birthdate', 'institution', 'expiration_date', - 'patron_type', 'patron_types' - ] - res = client.get(url) + # full information with all scopes + res = client.get( + url_for('api_patrons.info', access_token=token.access_token)) assert res.status_code == 200 assert res.json == { 'barcode':