Skip to content

Commit 4e1cbc7

Browse files
authored
Merge pull request #1769 from RCOSDP/feature/H2025-01_v0.9.26_hiroba
Feature/h2025 01 v0.9.26 hiroba
2 parents fd909fd + 3a359c9 commit 4e1cbc7

22 files changed

Lines changed: 745 additions & 68 deletions

File tree

docs/source/developer/database.rst

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6161,7 +6161,7 @@ shibboleth_user
61616161
-
61626162
* - shib_eppn
61636163
- shib_eppn
6164-
- VARCHAR(128)
6164+
- VARCHAR(2310)
61656165
- True
61666166
- False
61676167
- None
@@ -6189,7 +6189,7 @@ shibboleth_user
61896189
-
61906190
* - shib_page_name
61916191
- shib_page_name
6192-
- VARCHAR(255)
6192+
- VARCHAR(1024)
61936193
- False
61946194
- False
61956195
- None
@@ -6222,6 +6222,13 @@ shibboleth_user
62226222
- False
62236223
- None
62246224
-
6225+
* - shib_organization
6226+
- shib_organization
6227+
- VARCHAR(255)
6228+
- False
6229+
- False
6230+
- None
6231+
-
62256232

62266233
Keys
62276234
^^^^

modules/invenio-records-rest/invenio_records_rest/views.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,8 @@ def redirect_to_search(page, size):
469469
if size:
470470
url += "&size=" + str(size)
471471
get_args = request.args.to_dict()
472+
if get_args.get('format') != 'html':
473+
get_args['format'] = 'html'
472474
for key, param in get_args.items():
473475
if key == "page_no" or key == "list_view_num" \
474476
or key == "log_term" or key == "lang":
@@ -583,8 +585,8 @@ def get(self, **kwargs):
583585
'list_view_num', 10, type=int),
584586
type=int)
585587
size = RecordsListResource.adjust_list_view_num(size)
586-
format = request.values.get('format')
587-
if (not format or format == "html") and request.values.get('q') == None:
588+
formats = request.values.getlist('format')
589+
if (not formats or 'html' in formats) and request.values.get('q') == None:
588590
return redirect_to_search(page, size)
589591

590592
# if page * size >= self.max_result_window:
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
# -*- coding: utf-8 -*-
2+
#
3+
# This file is part of Invenio.
4+
# Copyright (C) 2016-2018 CERN.
5+
#
6+
# Invenio is free software; you can redistribute it and/or modify it
7+
# under the terms of the MIT License; see LICENSE file for more details.
8+
"""Tests for patching records."""
9+
10+
import pytest
11+
from flask import Flask, url_for
12+
from flask_login import AnonymousUserMixin
13+
import flask_security
14+
from invenio_records_rest.views import RecordsListResource
15+
from werkzeug.test import EnvironBuilder
16+
from werkzeug.wrappers import Request
17+
18+
class DummyUser(AnonymousUserMixin):
19+
is_authenticated = False
20+
id = None
21+
22+
class DummySearch:
23+
def with_preference_param(self):
24+
return self
25+
def params(self, **kwargs):
26+
return self
27+
def to_dict(self):
28+
return {"sort": [{"control_number": {"order": "desc"}}]}
29+
def __getitem__(self, key):
30+
return self
31+
def execute(self):
32+
class Result:
33+
hits = type('hits', (), {'total': 0})()
34+
def to_dict(self):
35+
return {}
36+
return Result()
37+
38+
def make_request(app, query_string=None):
39+
builder = EnvironBuilder(method='GET', query_string=query_string)
40+
env = builder.get_environ()
41+
req = Request(env)
42+
return req
43+
44+
@pytest.fixture
45+
def resource_with_dummy_search(app):
46+
def dummy_search_factory(self, search):
47+
return search, {}
48+
49+
return RecordsListResource(
50+
minter_name="recid",
51+
pid_type="recid",
52+
pid_fetcher="recid",
53+
read_permission_factory=None,
54+
create_permission_factory=None,
55+
list_permission_factory=None,
56+
search_class=DummySearch,
57+
record_serializers={},
58+
record_loaders=None,
59+
search_serializers={'application/json': lambda *a, **k: {}},
60+
default_media_type='application/json',
61+
max_result_window=10000,
62+
search_factory=dummy_search_factory,
63+
item_links_factory=None,
64+
record_class=None,
65+
indexer_class=None
66+
)
67+
68+
def test_format_html_redirect(monkeypatch, app, resource_with_dummy_search):
69+
# Should redirect when format=html is specified
70+
with app.test_request_context('/?format=html'):
71+
monkeypatch.setattr(flask_security, "current_user", DummyUser())
72+
monkeypatch.setattr('flask.url_for', lambda endpoint, **kwargs: '/dummy_url')
73+
monkeypatch.setattr('invenio_records_rest.views.url_for', lambda endpoint, **kwargs: '/dummy_url')
74+
monkeypatch.setattr('invenio_accounts.models.User', type('User', (), {'query': type('query', (), {'get': staticmethod(lambda x: type('U', (), {'email': 'dummy@example.com'})())})()}) )
75+
resp = resource_with_dummy_search.get()
76+
assert resp.status_code == 302
77+
assert 'search' in resp.location
78+
79+
def test_format_rss(monkeypatch, app, resource_with_dummy_search):
80+
# Should NOT redirect when format=rss is specified
81+
with app.test_request_context('/?format=rss&q=test'):
82+
monkeypatch.setattr(flask_security, "current_user", DummyUser())
83+
monkeypatch.setattr('flask.url_for', lambda endpoint, **kwargs: '/dummy_url')
84+
monkeypatch.setattr('invenio_records_rest.views.url_for', lambda endpoint, **kwargs: '/dummy_url')
85+
monkeypatch.setattr('invenio_accounts.models.User', type('User', (), {'query': type('query', (), {'get': staticmethod(lambda x: type('U', (), {'email': 'dummy@example.com'})())})()}) )
86+
resp = resource_with_dummy_search.get()
87+
# Should return a dict as search result, not a redirect
88+
assert isinstance(resp, dict)
89+
90+
def test_format_multiple(monkeypatch, app, resource_with_dummy_search):
91+
# Should prioritize html when both format=html&format=rss are specified
92+
with app.test_request_context('/?format=html&format=rss'):
93+
monkeypatch.setattr('flask_security.current_user', DummyUser())
94+
monkeypatch.setattr('flask.url_for', lambda endpoint, **kwargs: '/dummy_url')
95+
monkeypatch.setattr('invenio_records_rest.views.url_for', lambda endpoint, **kwargs: '/dummy_url')
96+
monkeypatch.setattr('invenio_accounts.models.User', type('User', (), {'query': type('query', (), {'get': staticmethod(lambda x: type('U', (), {'email': 'dummy@example.com'})())})()}) )
97+
resp = resource_with_dummy_search.get()
98+
assert resp.status_code == 302
99+
assert 'search' in resp.location
100+
101+
def test_no_format_no_query(monkeypatch, app, resource_with_dummy_search):
102+
# Should redirect when neither format nor q is specified
103+
with app.test_request_context('/'):
104+
monkeypatch.setattr('flask_security.current_user', DummyUser())
105+
monkeypatch.setattr('flask.url_for', lambda endpoint, **kwargs: '/dummy_url')
106+
monkeypatch.setattr('invenio_records_rest.views.url_for', lambda endpoint, **kwargs: '/dummy_url')
107+
monkeypatch.setattr('invenio_accounts.models.User', type('User', (), {'query': type('query', (), {'get': staticmethod(lambda x: type('U', (), {'email': 'dummy@example.com'})())})()}) )
108+
resp = resource_with_dummy_search.get()
109+
assert resp.status_code == 302
110+
assert 'search' in resp.location
111+
112+
# def test_redirect_to_search_sets_format_html(app):
113+
# Should always set format=html in redirect URL, even if other formats are specified
114+
from invenio_records_rest.views import redirect_to_search
115+
with app.test_request_context('/?format=rss&q=test&foo=bar'):
116+
resp = redirect_to_search(page=2, size=50)
117+
assert resp.status_code == 302
118+
location = resp.location
119+
assert 'format=html' in location
120+
assert 'page=2' in location
121+
assert 'size=50' in location
122+
assert 'foo=bar' in location
123+
assert 'q=test' in location
124+
assert location.startswith('http')
125+
126+
127+
def test_redirect_to_search_no_format(app):
128+
# Should add format=html if no format is specified, and preserve other parameters
129+
from invenio_records_rest.views import redirect_to_search
130+
with app.test_request_context('/?q=xyz'):
131+
resp = redirect_to_search(page=3, size=75)
132+
assert resp.status_code == 302
133+
location = resp.location
134+
assert 'format=html' in location
135+
assert 'q=xyz' in location
136+
assert 'page=3' in location
137+
assert 'size=75' in location
138+
139+
def test_redirect_to_search_page_size_falsy(app):
140+
# Should not include page or size in URL if they are None, but should include format=html and other params
141+
from invenio_records_rest.views import redirect_to_search
142+
with app.test_request_context('/?format=xml&q=abc'):
143+
resp = redirect_to_search(page=None, size=None)
144+
location = resp.location
145+
assert 'page=None' not in location
146+
assert 'size=None' not in location
147+
assert 'format=html' in location
148+
assert 'q=abc' in location
149+
150+
def test_redirect_to_search_exclude_keys(app):
151+
# Should exclude specific keys (page_no, list_view_num, log_term, lang) from the redirect URL, but include others
152+
from invenio_records_rest.views import redirect_to_search
153+
with app.test_request_context('/?page_no=5&list_view_num=99&log_term=foo&lang=ja&q=zzz'):
154+
resp = redirect_to_search(page=1, size=20)
155+
location = resp.location
156+
# Excluded keys should not be in the URL
157+
assert 'page_no=' not in location
158+
assert 'list_view_num=' not in location
159+
assert 'log_term=' not in location
160+
assert 'lang=' not in location
161+
# Other parameters should be present
162+
assert 'q=zzz' in location
163+
assert 'page=1' in location
164+
assert 'size=20' in location
165+
assert 'format=html' in location
166+

modules/weko-accounts/tests/test_api.py

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from flask_login.utils import login_user
77
from invenio_accounts.models import Role, User
88
from weko_user_profiles.models import UserProfile
9+
from sqlalchemy.exc import SQLAlchemyError
910
from weko_accounts.models import ShibbolethUser
1011
from weko_accounts.api import ShibUser,get_user_info_by_role_name
1112

@@ -100,27 +101,26 @@ def test__create_unknown_roles(self, app, users, mocker):
100101
# def get_relation_info(self):
101102
# .tox/c1/bin/pytest --cov=weko_accounts tests/test_api.py::TestShibUser::test_get_relation_info -vv -s --cov-branch --cov-report=term --basetemp=/code/modules/weko-accounts/.tox/c1/tmp
102103
def test_get_relation_info(self,app,db,users):
103-
104+
104105
user1 = users[0]["obj"]
105106
user2 = users[1]["obj"]
107+
106108
attr = {
107-
"shib_eppn":"test_eppn"
109+
"shib_eppn": "test_eppn",
110+
"shib_mail": None,
111+
"shib_user_name": None,
112+
"shib_role_authority_name": None,
113+
"shib_page_name": None,
114+
"shib_active_flag": None,
115+
"shib_ip_range_flag": None,
116+
"shib_organization": None
108117
}
109118
s_user1 = ShibbolethUser(weko_uid=user1.id,weko_user=user1,**attr)
110119
db.session.add(s_user1)
111120
db.session.commit()
112121

113122
# exist shib_eppn,exist shib_user.weko_user,not exist self.user
114123
# attribute does not exist
115-
attr = {
116-
"shib_eppn":"test_eppn",
117-
"shib_mail":None,
118-
"shib_user_name":None,
119-
"shib_role_authority_name":None,
120-
"shib_page_name":None,
121-
"shib_active_flag":None,
122-
"shib_ip_range_flag":None,
123-
}
124124
shibuser = ShibUser(attr)
125125
result = shibuser.get_relation_info()
126126
assert result.shib_mail == None
@@ -129,6 +129,7 @@ def test_get_relation_info(self,app,db,users):
129129
assert result.shib_page_name == None
130130
assert result.shib_active_flag == None
131131
assert result.shib_ip_range_flag == None
132+
assert result.shib_organization == None
132133

133134
# attribute exists
134135
attr = {
@@ -139,6 +140,7 @@ def test_get_relation_info(self,app,db,users):
139140
"shib_page_name":"shib page",
140141
"shib_active_flag":"TRUE",
141142
"shib_ip_range_flag":"TRUE",
143+
"shib_organization":"shib org"
142144
}
143145
shibuser = ShibUser(attr)
144146
result = shibuser.get_relation_info()
@@ -148,11 +150,18 @@ def test_get_relation_info(self,app,db,users):
148150
assert result.shib_page_name == "shib page"
149151
assert result.shib_active_flag == "TRUE"
150152
assert result.shib_ip_range_flag == "TRUE"
151-
153+
assert result.shib_organization == "shib org"
154+
152155
# not exist shib_eppn,not exist shib_user.weko_user
153156
attr = {
154157
"shib_eppn":"",
155-
"shib_user_name":"shib name2"
158+
"shib_user_name":"shib name2",
159+
"shib_mail":None,
160+
"shib_role_authority_name":None,
161+
"shib_page_name":None,
162+
"shib_active_flag":None,
163+
"shib_ip_range_flag":None,
164+
"shib_organization":None
156165
}
157166
s_user2 = ShibbolethUser(**attr)
158167
db.session.add(s_user2)
@@ -161,15 +170,15 @@ def test_get_relation_info(self,app,db,users):
161170
result = shibuser.get_relation_info()
162171
assert result == None
163172

164-
# not exist shib_eppn, exist shib_user.weko_user,exist self.user, raise Exception
173+
# not exist shib_eppn, exist shib_user.weko_user,exist self.user, raise SQLAlchemyError
165174
s_user2.weko_user = user2
166175
s_user2.weko_uid = user2.id
167176
db.session.merge(s_user2)
168177
db.session.commit()
169178
shibuser.user = user2
170-
with patch("weko_accounts.api.db.session.commit",side_effect=Exception):
171-
result = shibuser.get_relation_info()
172-
assert result == None
179+
with patch("weko_accounts.api.db.session.commit",side_effect=SQLAlchemyError):
180+
with pytest.raises(SQLAlchemyError):
181+
shibuser.get_relation_info()
173182
# def check_weko_user(self, account, pwd):
174183
# .tox/c1/bin/pytest --cov=weko_accounts tests/test_api.py::TestShibUser::test_check_weko_user -vv -s --cov-branch --cov-report=term --basetemp=/code/modules/weko-accounts/.tox/c1/tmp
175184
def test_check_weko_user(self,app,users):

modules/weko-accounts/weko_accounts/api.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,8 @@ def get_relation_info(self):
147147
shib_user.shib_active_flag = self.shib_attr['shib_active_flag']
148148
if self.shib_attr['shib_ip_range_flag']:
149149
shib_user.shib_ip_range_flag = self.shib_attr['shib_ip_range_flag']
150+
if self.shib_attr['shib_organization']:
151+
shib_user.shib_organization = self.shib_attr['shib_organization']
150152
db.session.commit()
151153
except SQLAlchemyError as ex:
152154
current_app.logger.error("SQLAlchemyError: {}".format(ex))

modules/weko-accounts/weko_accounts/config.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
'SHIB_ATTR_SITE_USER_WITHIN_IP_RANGE_FLAG': (False, 'shib_ip_range_flag'),
7272
'SHIB_ATTR_MAIL': (False, 'shib_mail'),
7373
'SHIB_ATTR_USER_NAME': (False, 'shib_user_name'),
74+
'SHIB_ATTR_ORGANIZATION': (False, 'shib_organization'),
7475
}
7576
"""IdP attribute map."""
7677

modules/weko-accounts/weko_accounts/models.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ class ShibbolethUser(db.Model):
7171
shib_ip_range_flag = db.Column(db.String(255), nullable=True)
7272
"""SHIB_ATTR_SITE_USER_WITHIN_IP_RANGE_FLAG"""
7373

74+
shib_organization = db.Column(db.String(255), nullable=True)
75+
"""SHIB_ATTR_ORGANIZATION"""
76+
7477
shib_roles = db.relationship(
7578
'Role',
7679
secondary=shibuserrole,

modules/weko-items-ui/tests/conftest.py

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -345,26 +345,31 @@ def db(app):
345345

346346
@pytest.fixture()
347347
def esindex(app,db_records):
348+
current_search_client.indices.delete(index='test-*')
348349
with open("tests/data/mappings/item-v1.0.0.json","r") as f:
349350
mapping = json.load(f)
351+
with open("tests/data/mappings/record-view-v1.json","r") as f:
352+
mapping_record_view = json.load(f)
350353

351354
search = LocalProxy(lambda: app.extensions["invenio-search"])
352355

353356
with app.test_request_context():
354-
search.client.indices.create(app.config["INDEXER_DEFAULT_INDEX"],body=mapping)
355-
search.client.indices.put_alias(index=app.config["INDEXER_DEFAULT_INDEX"], name="test-weko")
357+
current_search_client.indices.create(app.config["INDEXER_DEFAULT_INDEX"],body=mapping)
358+
current_search_client.indices.put_alias(index=app.config["INDEXER_DEFAULT_INDEX"], name="test-weko")
356359
# print(current_search_client.indices.get_alias())
360+
current_search_client.indices.create("test-stats-record-view-000001",body=mapping_record_view)
361+
current_search_client.indices.put_alias(index="test-stats-record-view-000001",name="test-stats-record-view")
357362

358363
for depid, recid, parent, doi, record, item in db_records:
359-
search.client.index(index='test-weko-item-v1.0.0', doc_type='item-v1.0.0', id=record.id, body=record,refresh='true')
364+
current_search_client.index(index='test-weko-item-v1.0.0', doc_type='item-v1.0.0', id=record.id, body=record,refresh='true')
360365

361-
362-
yield search
366+
yield current_search_client
363367

364368
with app.test_request_context():
365-
search.client.indices.delete_alias(index=app.config["INDEXER_DEFAULT_INDEX"], name="test-weko")
366-
search.client.indices.delete(index=app.config["INDEXER_DEFAULT_INDEX"], ignore=[400, 404])
367-
369+
current_search_client.indices.delete_alias(index=app.config["INDEXER_DEFAULT_INDEX"], name="test-weko")
370+
current_search_client.indices.delete(index=app.config["INDEXER_DEFAULT_INDEX"], ignore=[400, 404])
371+
#current_search_client.indices.delete_alias(index="test-stats-record-view-000001",name="test-stats-record-view")
372+
#current_search_client.indices.delete(index="test-stats-record-view-000001", ignore=[400,400])
368373

369374

370375
@pytest.fixture()

0 commit comments

Comments
 (0)