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

oauth: adds user_id and patron_info #3786

Merged
merged 1 commit into from
Dec 5, 2024
Merged
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
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -319,11 +319,12 @@ vendors = "rero_ils.modules.vendors.jsonschemas"
files = "rero_ils.modules.files.jsonschemas"

[tool.poetry.plugins."invenio_oauth2server.scopes"]
fullname = "rero_ils.oauth.scopes:fullname"
birthdate = "rero_ils.oauth.scopes:birthdate"
expiration_date = "rero_ils.oauth.scopes:expiration_date"
fullname = "rero_ils.oauth.scopes:fullname"
institution = "rero_ils.oauth.scopes:institution"
patron_type = "rero_ils.oauth.scopes:patron_type"
# deprecated scopes
patron_types = "rero_ils.oauth.scopes:patron_types"

[tool.poetry.plugins."invenio_pidstore.fetchers"]
Expand Down
113 changes: 50 additions & 63 deletions rero_ils/modules/patrons/views.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
#
# RERO ILS
# Copyright (C) 2019-2023 RERO
# Copyright (C) 2024 RERO
#
# 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
Expand All @@ -19,7 +19,6 @@

from __future__ import absolute_import, print_function

import copy
import datetime
import re

Expand Down Expand Up @@ -321,78 +320,66 @@ def info():
"""Get patron info."""
token_scopes = flask_request.oauth.access_token.scopes

def get_main_patron(patrons):
"""Return the main patron.

:param patrons: List of patrons.
:returns: The main patron.
"""
# TODO: Find a way to determine which is the main patron.
return patrons[0]

def get_institution_code(institution):
"""Get the institution code for a given institution.

Special transformation for `nj`.

: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"

user = User.get_record(current_user.id).dumps_metadata()

# Process for all patrons
patrons = copy.deepcopy(current_patrons)
for patron in patrons:
patron["institution"] = patron.organisation
patron["patron"]["type"] = PatronType.get_record_by_pid(
extracted_data_from_ref(patron["patron"]["type"]["$ref"])
)

# Birthdate
data = {}
birthdate = current_user.user_profile.get("birth_date")
if "birthdate" in token_scopes and birthdate:
data["birthdate"] = birthdate
data = {"user_id": current_user.id}
# Full name
name_parts = [
current_user.user_profile.get("last_name", "").strip(),
current_user.user_profile.get("first_name", "").strip(),
]
fullname = ", ".join(filter(None, name_parts))
if "fullname" in token_scopes and fullname:
if fullname and "fullname" in token_scopes:
data["fullname"] = fullname
birthdate = current_user.user_profile.get("birth_date")
# Birthdate
if birthdate and "birthdate" in token_scopes:
data["birthdate"] = birthdate

# No patrons found for user
if not patrons:
return jsonify(data)

# Get the main patron
patron = get_main_patron(patrons)
# Barcode
if patron.get("patron", {}).get("barcode"):
data["barcode"] = patron["patron"]["barcode"][0]
# Patron types
if "patron_types" in token_scopes:
patron_types = []
for patron in patrons:
info = {}
patron_type_code = patron.get("patron", {}).get("type", {}).get("code")
if patron_type_code:
patrons = current_patrons
if patrons:
patron = patrons[0]
# Barcode
if patron.get("patron", {}).get("barcode"):
data["barcode"] = patron["patron"]["barcode"][0]
# Patron
patron_types = []
patron_infos = {}
for patron in patrons:
patron_type = PatronType.get_record_by_pid(
extracted_data_from_ref(patron["patron"]["type"]["$ref"])
)
patron_type_code = patron_type.get("code")
institution = patron.organisation["code"]
expiration_date = patron.get("patron", {}).get("expiration_date")

# old list (patron_types)
if "patron_types" in token_scopes:
info = {"patron_pid": patron.pid}
if patron_type_code and "patron_type" in token_scopes:
info["patron_type"] = patron_type_code
if patron.get("institution"):
info["institution"] = get_institution_code(patron["institution"])
if patron.get("patron", {}).get("expiration_date"):
if institution and "institution" in token_scopes:
info["institution"] = institution
if expiration_date and "expiration_date" in token_scopes:
info["expiration_date"] = datetime.datetime.strptime(
patron["patron"]["expiration_date"], "%Y-%m-%d"
expiration_date, "%Y-%m-%d"
).isoformat()
if info:
patron_types.append(info)
if patron_types:
data["patron_types"] = patron_types

patron_types.append(info)

# new dict (patron_info)
patron_info = {"patron_pid": patron.pid}
if institution and "institution" in token_scopes:
patron_info["institution"] = institution
if patron_type_code and "patron_type" in token_scopes:
patron_info["patron_type"] = patron_type_code
if expiration_date and "expiration_date" in token_scopes:
patron_info["expiration_date"] = datetime.datetime.strptime(
expiration_date, "%Y-%m-%d"
).isoformat()
patron_infos[institution] = patron_info

if patron_types:
data["patron_types"] = patron_types
if patron_infos:
data["patron_info"] = patron_infos
return jsonify(data)


Expand Down
8 changes: 5 additions & 3 deletions rero_ils/oauth/scopes.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
#
# RERO ILS
# Copyright (C) 2021 RERO
# Copyright (C) 2024 RERO
#
# 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
Expand All @@ -21,7 +21,9 @@

fullname = Scope("fullname", help_text="Full name", group="User")
birthdate = Scope("birthdate", help_text="Birthdate", group="User")
institution = Scope("institution", help_text="Institution", group="User")
expiration_date = Scope("expiration_date", help_text="Expiration date", group="User")
institution = Scope("institution", help_text="Institution", group="User")
patron_type = Scope("patron_type", help_text="Patron type", group="User")
patron_types = Scope("patron_types", help_text="Patron types", group="User")
patron_types = Scope(
"patron_types", help_text="Patron types (deprecated)", group="User"
)
6 changes: 4 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -370,10 +370,12 @@ def run(self):
'invenio_oauth2server.scopes': [
'fullname = rero_ils.oauth.scopes:fullname',
'birthdate = rero_ils.oauth.scopes:birthdate',
'institution = rero_ils.oauth.scopes:institution',
'patron_info = rero_ils.oauth.scopes:patron_info',
'expiration_date = rero_ils.oauth.scopes:expiration_date',
'institution = rero_ils.oauth.scopes:institution',
'patron_type = rero_ils.oauth.scopes:patron_type',
'patron_types = rero_ils.oauth.scopes:patron_types'
# deprecated scopes
'patron_types = rero_ils.oauth.scopes:patron_types',
]
},
classifiers=[
Expand Down
28 changes: 24 additions & 4 deletions tests/api/patrons/test_patrons_rest.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
#
# RERO ILS
# Copyright (C) 2019 RERO
# Copyright (C) 2024 RERO
#
# 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
Expand Down Expand Up @@ -545,31 +545,51 @@ def test_patron_info(app, client, patron_martigny, librarian_martigny):
url_for("api_patrons.info", access_token=no_scope_token.access_token)
)
assert res.status_code == 200
assert res.json == {"barcode": patron_martigny["patron"]["barcode"].pop()}
barcode = patron_martigny["patron"]["barcode"].pop()
assert res.json == {
"barcode": barcode,
"user_id": patron_martigny.user.id,
"patron_info": {"org1": {"patron_pid": patron_martigny.pid}},
}

# 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": "4098124352",
"barcode": barcode,
"user_id": patron_martigny.user.id,
"birthdate": "1947-06-07",
"fullname": "Roduit, Louis",
"patron_types": [
{
"expiration_date": patron_martigny["patron"]["expiration_date"]
+ "T00:00:00",
"institution": "org1",
"patron_pid": patron_martigny.pid,
"patron_type": "patron-code",
}
],
"patron_info": {
"org1": {
"expiration_date": patron_martigny["patron"]["expiration_date"]
+ "T00:00:00",
"institution": "org1",
"patron_pid": patron_martigny.pid,
"patron_type": "patron-code",
}
},
}

# librarian information with all scopes
res = client.get(
url_for("api_patrons.info", access_token=librarian_token.access_token)
)
assert res.status_code == 200
assert res.json == {"birthdate": "1965-02-07", "fullname": "Pedronni, Marie"}
assert res.json == {
"birthdate": "1965-02-07",
"fullname": "Pedronni, Marie",
"user_id": librarian_martigny.user.id,
}


def test_patrons_search(client, librarian_martigny):
Expand Down
Loading