invenio-app-ils 4.5.0__py2.py3-none-any.whl → 5.0.0__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. invenio_app_ils/__init__.py +1 -1
  2. invenio_app_ils/assets/semantic-ui/less/theme.config +103 -0
  3. invenio_app_ils/circulation/api.py +9 -5
  4. invenio_app_ils/circulation/config.py +1 -0
  5. invenio_app_ils/circulation/loaders/schemas/json/loan_checkout.py +1 -1
  6. invenio_app_ils/circulation/loaders/schemas/json/loan_request.py +2 -2
  7. invenio_app_ils/circulation/notifications/api.py +9 -1
  8. invenio_app_ils/circulation/notifications/messages.py +2 -1
  9. invenio_app_ils/circulation/templates/invenio_app_ils_circulation/notifications/update_dates.html +19 -0
  10. invenio_app_ils/cli.py +92 -64
  11. invenio_app_ils/config.py +10 -2
  12. invenio_app_ils/documents/loaders/jsonschemas/document.py +1 -1
  13. invenio_app_ils/eitems/loaders/jsonschemas/eitems.py +2 -2
  14. invenio_app_ils/patrons/anonymization.py +0 -4
  15. invenio_app_ils/series/loaders/jsonschemas/series.py +1 -1
  16. invenio_app_ils/webpack.py +27 -0
  17. {invenio_app_ils-4.5.0.dist-info → invenio_app_ils-5.0.0.dist-info}/METADATA +56 -43
  18. {invenio_app_ils-4.5.0.dist-info → invenio_app_ils-5.0.0.dist-info}/RECORD +24 -112
  19. {invenio_app_ils-4.5.0.dist-info → invenio_app_ils-5.0.0.dist-info}/entry_points.txt +3 -0
  20. {invenio_app_ils-4.5.0.dist-info → invenio_app_ils-5.0.0.dist-info}/top_level.txt +0 -1
  21. invenio_app_ils/notifications/admin.py +0 -57
  22. tests/__init__.py +0 -8
  23. tests/api/__init__.py +0 -8
  24. tests/api/acquisition/__init__.py +0 -8
  25. tests/api/acquisition/test_acq_orders_crud.py +0 -99
  26. tests/api/acquisition/test_acq_orders_permissions.py +0 -104
  27. tests/api/acquisition/test_acq_providers_permissions.py +0 -83
  28. tests/api/circulation/__init__.py +0 -8
  29. tests/api/circulation/test_expired_loans.py +0 -88
  30. tests/api/circulation/test_loan_bulk_extend.py +0 -169
  31. tests/api/circulation/test_loan_checkout.py +0 -422
  32. tests/api/circulation/test_loan_default_durations.py +0 -43
  33. tests/api/circulation/test_loan_document_resolver.py +0 -18
  34. tests/api/circulation/test_loan_extend.py +0 -122
  35. tests/api/circulation/test_loan_item_permissions.py +0 -135
  36. tests/api/circulation/test_loan_item_resolver.py +0 -26
  37. tests/api/circulation/test_loan_list_permissions.py +0 -98
  38. tests/api/circulation/test_loan_patron_resolver.py +0 -38
  39. tests/api/circulation/test_loan_request.py +0 -338
  40. tests/api/circulation/test_loan_update.py +0 -150
  41. tests/api/circulation/test_notifications.py +0 -221
  42. tests/api/conftest.py +0 -227
  43. tests/api/document_requests/__init__.py +0 -8
  44. tests/api/document_requests/test_document_requests.py +0 -131
  45. tests/api/document_requests/test_document_requests_permissions.py +0 -159
  46. tests/api/document_requests/test_notifications_filter.py +0 -35
  47. tests/api/ill/__init__.py +0 -8
  48. tests/api/ill/test_ill_brw_crud.py +0 -74
  49. tests/api/ill/test_ill_brw_reqs_patron_loan_create_action.py +0 -198
  50. tests/api/ill/test_ill_brw_reqs_patron_loan_extension_actions.py +0 -280
  51. tests/api/ill/test_ill_brw_reqs_permissions.py +0 -163
  52. tests/api/ill/test_ill_providers_permissions.py +0 -82
  53. tests/api/ils/__init__.py +0 -8
  54. tests/api/ils/documents/__init__.py +0 -8
  55. tests/api/ils/documents/test_document_crud.py +0 -57
  56. tests/api/ils/documents/test_document_permissions.py +0 -100
  57. tests/api/ils/documents/test_document_resolvers.py +0 -35
  58. tests/api/ils/eitems/__init__.py +0 -8
  59. tests/api/ils/eitems/test_eitems_crud.py +0 -42
  60. tests/api/ils/eitems/test_eitems_permissions.py +0 -85
  61. tests/api/ils/eitems/test_files.py +0 -162
  62. tests/api/ils/items/__init__.py +0 -8
  63. tests/api/ils/items/test_apis.py +0 -43
  64. tests/api/ils/items/test_items_crud.py +0 -99
  65. tests/api/ils/items/test_items_permissions.py +0 -107
  66. tests/api/ils/records_relations/__init__.py +0 -8
  67. tests/api/ils/records_relations/helpers.py +0 -115
  68. tests/api/ils/records_relations/test_records_relations_parentchild.py +0 -560
  69. tests/api/ils/records_relations/test_records_relations_sequence.py +0 -294
  70. tests/api/ils/records_relations/test_records_relations_siblings.py +0 -751
  71. tests/api/ils/series/__init__.py +0 -8
  72. tests/api/ils/series/test_series_permissions.py +0 -95
  73. tests/api/ils/test_anonymization.py +0 -181
  74. tests/api/ils/test_apis.py +0 -76
  75. tests/api/ils/test_closures.py +0 -353
  76. tests/api/ils/test_errors.py +0 -125
  77. tests/api/ils/test_facets.py +0 -88
  78. tests/api/ils/test_internal_locations.py +0 -96
  79. tests/api/ils/test_loaders.py +0 -51
  80. tests/api/ils/test_metadata_extensions.py +0 -206
  81. tests/api/ils/test_notifications.py +0 -173
  82. tests/api/ils/test_notifications_mails.py +0 -37
  83. tests/api/ils/test_notifications_permissions.py +0 -55
  84. tests/api/ils/test_patrons.py +0 -102
  85. tests/api/ils/test_record_delete.py +0 -42
  86. tests/api/ils/test_record_permissions.py +0 -132
  87. tests/api/ils/test_resolvers.py +0 -205
  88. tests/api/ils/test_stats.py +0 -142
  89. tests/api/ils/test_tasks.py +0 -209
  90. tests/api/ils/test_vocabularies.py +0 -35
  91. tests/conftest.py +0 -221
  92. tests/data/acq_orders.json +0 -110
  93. tests/data/acq_providers.json +0 -12
  94. tests/data/document_requests.json +0 -77
  95. tests/data/documents.json +0 -238
  96. tests/data/eitems.json +0 -71
  97. tests/data/ill_borrowing_requests.json +0 -77
  98. tests/data/ill_providers.json +0 -12
  99. tests/data/internal_locations.json +0 -22
  100. tests/data/items.json +0 -304
  101. tests/data/loans.json +0 -133
  102. tests/data/loans_most_loaned.json +0 -128
  103. tests/data/locations.json +0 -26
  104. tests/data/series.json +0 -33
  105. tests/helpers.py +0 -107
  106. tests/templates/notifications/title_body.html +0 -8
  107. tests/templates/notifications/title_body_html.html +0 -13
  108. tests/templates/notifications/title_body_html_ctx.html +0 -13
  109. tests/templates/notifications/title_only.html +0 -3
  110. tests/test_post_logout_redirect.py +0 -23
  111. tests/test_version.py +0 -17
  112. /tests/templates/notifications/blank.html → /invenio_app_ils/assets/semantic-ui/templates/.gitkeep +0 -0
  113. {invenio_app_ils-4.5.0.dist-info → invenio_app_ils-5.0.0.dist-info}/WHEEL +0 -0
  114. {invenio_app_ils-4.5.0.dist-info → invenio_app_ils-5.0.0.dist-info}/licenses/AUTHORS.rst +0 -0
  115. {invenio_app_ils-4.5.0.dist-info → invenio_app_ils-5.0.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,132 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- #
3
- # Copyright (C) 2018-2019 CERN.
4
- #
5
- # invenio-app-ils is free software; you can redistribute it and/or modify it
6
- # under the terms of the MIT License; see LICENSE file for more details.
7
-
8
- """Test record permissions."""
9
-
10
- import uuid
11
-
12
- import pytest
13
- from flask_principal import RoleNeed, identity_loaded
14
- from invenio_access.models import ActionRoles
15
- from invenio_accounts.models import Role
16
- from invenio_records.api import Record
17
- from invenio_search.api import RecordsSearch
18
-
19
- from invenio_app_ils.errors import UnauthorizedSearchError
20
- from invenio_app_ils.records.permissions import RecordPermission, create_records_action
21
- from invenio_app_ils.search_permissions import _filter_by_patron
22
- from tests.helpers import user_login
23
-
24
-
25
- @pytest.mark.parametrize(
26
- "patron_pid,qs,should_raise",
27
- [
28
- ("1", None, False),
29
- ("1", "", False),
30
- ("1", "pid:1234", False),
31
- ("1", "patron_pid:2", True),
32
- ("1", "patron_pid: 2", True),
33
- ("1", "patron_pid: '2'", False),
34
- ("1", "pid:1234 AND patron_pid:2", True),
35
- ],
36
- )
37
- def test_filter_by_patron(app, patron_pid, qs, should_raise):
38
- """Test the function filter_by_patron."""
39
- search = RecordsSearch()
40
- if should_raise:
41
- with pytest.raises(UnauthorizedSearchError):
42
- _filter_by_patron(patron_pid, search, qs)
43
- else:
44
- _search, _qs = _filter_by_patron(patron_pid, search, qs)
45
- term = _search.to_dict()["query"]["bool"]["filter"][0]["term"]
46
- assert term == {"patron_pid": patron_pid}
47
-
48
-
49
- def test_record_generic_access(client, db, users, with_access):
50
- """Test access control for records."""
51
-
52
- tests = [
53
- ({"foo": "bar"}, "read", True),
54
- ({"foo": "bar"}, "update", False),
55
- ({"_access": {"read": [1]}}, "read", True),
56
- ({"_access": {"read": [2]}}, "read", False),
57
- ({"_access": {"read": ["records-readers"]}}, "read", True),
58
- # permission for specific user to create
59
- ({"_access": {"update": [1]}}, "update", True),
60
- # checks if the access works for different actions
61
- ({"_access": {"update": [1]}}, "create", False),
62
- ({"_access": {"delete": [1]}}, "update", False),
63
- # delete access for user and librarian
64
- ({"_access": {"delete": [1, "librarian"]}}, "delete", True),
65
- ]
66
-
67
- @identity_loaded.connect
68
- def add_roles_to_identity(sender, identity):
69
- """Provide additional role to the user."""
70
- roles = [RoleNeed("records-readers")]
71
- identity.provides |= set(roles)
72
-
73
- def login_and_test(username):
74
- user = user_login(client, username, users)
75
- # Create record
76
- id = uuid.uuid4()
77
- record = Record.create(access, id_=id)
78
- factory = RecordPermission(record, action)
79
- if user.has_role("admin"):
80
- # super user can do EVERYTHING
81
- assert factory.can()
82
- elif user.has_role("librarian") and action != "delete":
83
- # librarian should be able to update, create, and read everything
84
- assert factory.can()
85
- else:
86
- assert factory.can() if is_allowed else not factory.can()
87
-
88
- for access, action, is_allowed in tests:
89
- # Test standard user
90
- login_and_test("patron1")
91
- # Test librarian access
92
- login_and_test("librarian")
93
- # Test superuser access
94
- login_and_test("admin")
95
-
96
-
97
- @pytest.fixture()
98
- def with_role_creator(db):
99
- """ "Create a new role and assign action."""
100
- role = Role(name="records-creators")
101
- db.session.add(role)
102
- db.session.commit()
103
- # assign role to the action "create-records"
104
- ar = ActionRoles.allow(create_records_action, role_id=role.id)
105
- db.session.add(ar)
106
- db.session.commit()
107
-
108
-
109
- def test_record_patron_create(client, db, users, with_role_creator):
110
- """Test patron create."""
111
-
112
- tests = [
113
- ({"foo": "bar"}, "create", True),
114
- ({"foo": "bar"}, "update", False),
115
- ({"foo": "bar"}, "delete", False),
116
- ]
117
-
118
- @identity_loaded.connect
119
- def add_roles_to_identity(sender, identity):
120
- """Provide additional role to the user."""
121
- roles = [RoleNeed("records-creators")]
122
- identity.provides |= set(roles)
123
-
124
- for access, action, is_allowed in tests:
125
- # create role to be able to create records
126
- user_login(client, "patron1", users)
127
-
128
- id = uuid.uuid4()
129
- record = Record.create(access, id_=id)
130
- factory = RecordPermission(record, action)
131
-
132
- assert factory.can() if is_allowed else not factory.can()
@@ -1,205 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- #
3
- # Copyright (C) 2020 CERN.
4
- #
5
- # invenio-app-ils is free software; you can redistribute it and/or modify it
6
- # under the terms of the MIT License; see LICENSE file for more details.
7
-
8
- """Test Items resolvers."""
9
-
10
- from invenio_circulation.pidstore.pids import CIRCULATION_LOAN_PID_TYPE
11
-
12
- from invenio_app_ils.acquisition.api import ORDER_PID_TYPE
13
- from invenio_app_ils.document_requests.api import DOCUMENT_REQUEST_PID_TYPE
14
- from invenio_app_ils.documents.api import DOCUMENT_PID_TYPE, Document
15
- from invenio_app_ils.documents.indexer import DocumentIndexer
16
- from invenio_app_ils.eitems.api import EITEM_PID_TYPE, EItem
17
- from invenio_app_ils.eitems.indexer import EItemIndexer
18
- from invenio_app_ils.ill.api import BORROWING_REQUEST_PID_TYPE
19
- from invenio_app_ils.internal_locations.indexer import InternalLocationIndexer
20
- from invenio_app_ils.items.api import ITEM_PID_TYPE, Item
21
- from invenio_app_ils.items.indexer import ItemIndexer
22
- from invenio_app_ils.locations.api import LOCATION_PID_TYPE, Location
23
- from invenio_app_ils.locations.indexer import LocationIndexer
24
- from invenio_app_ils.patrons.api import PATRON_PID_TYPE, Patron
25
- from invenio_app_ils.patrons.indexer import PatronIndexer
26
-
27
- from invenio_app_ils.internal_locations.api import ( # isort:skip
28
- INTERNAL_LOCATION_PID_TYPE,
29
- InternalLocation,
30
- )
31
-
32
-
33
- def test_jsonresolvers(testdata, mocker):
34
- """Test that all records referencing a changed record are re-indexed."""
35
-
36
- def _get_mock():
37
- return mocker.patch("invenio_app_ils.indexer.ReferencedRecordsIndexer.index")
38
-
39
- def _assert_origin(indexer, pid_type, pid_value):
40
- """Assert that origin is called and return all referenced."""
41
- assert indexer.called
42
- all_calls = indexer.call_args_list
43
- first_call = all_calls[0]
44
- indexed, referenced = first_call[0]
45
- assert indexed["pid_type"] == pid_type
46
- assert indexed["record"]["pid"] == pid_value
47
-
48
- # call[0] is the list of arguments passed to the function
49
- # call[0][0] is the origin record, call[0][1] is the referenced record
50
- all_referenced = []
51
- for call in all_calls:
52
- origin, referenced = call[0]
53
- all_referenced += referenced
54
- return all_referenced
55
-
56
- def _assert_contains(referenced, pid_type):
57
- """Assert that given PID is contained in one of the referenced."""
58
- found = False
59
- for r in referenced:
60
- if r["pid_type"] == pid_type:
61
- found = True
62
- break
63
- assert found
64
-
65
- def test_on_document_update():
66
- """Test document resolvers."""
67
- indexer = _get_mock()
68
-
69
- pid = "docid-2"
70
- document = Document.get_record_by_pid(pid)
71
- DocumentIndexer().index(document)
72
-
73
- referenced = _assert_origin(indexer, DOCUMENT_PID_TYPE, pid)
74
-
75
- # should re-index document request
76
- n_doc_req = 1 # from test data
77
- _assert_contains(referenced, DOCUMENT_REQUEST_PID_TYPE)
78
-
79
- # should re-index eitem
80
- n_eitems = 1 # from test data
81
- _assert_contains(referenced, EITEM_PID_TYPE)
82
-
83
- # should re-index item
84
- n_items = 1 # from test data
85
- _assert_contains(referenced, ITEM_PID_TYPE)
86
-
87
- # should re-index acq
88
- n_acq = 1 # from test data
89
- _assert_contains(referenced, ORDER_PID_TYPE)
90
-
91
- # should re-index ill
92
- n_ill = 1 # from test data
93
- _assert_contains(referenced, BORROWING_REQUEST_PID_TYPE)
94
-
95
- expected_total = n_doc_req + n_eitems + n_items + n_acq + n_ill
96
- assert len(referenced) == expected_total
97
-
98
- def test_on_eitem_update():
99
- """Test eitem resolvers."""
100
- indexer = _get_mock()
101
-
102
- pid = "eitemid-1"
103
- eitem = EItem.get_record_by_pid(pid)
104
- EItemIndexer().index(eitem)
105
-
106
- referenced = _assert_origin(indexer, EITEM_PID_TYPE, pid)
107
-
108
- # should re-index documents
109
- n_documents = 1 # from test data
110
- _assert_contains(referenced, DOCUMENT_PID_TYPE)
111
-
112
- assert len(referenced) == n_documents
113
-
114
- def test_on_internal_location_update():
115
- """Test internal location resolvers."""
116
- indexer = _get_mock()
117
-
118
- pid = "ilocid-2"
119
- intloc = InternalLocation.get_record_by_pid(pid)
120
- InternalLocationIndexer().index(intloc)
121
-
122
- referenced = _assert_origin(indexer, INTERNAL_LOCATION_PID_TYPE, pid)
123
-
124
- # should re-index items
125
- n_items = 4 # from test data
126
- _assert_contains(referenced, ITEM_PID_TYPE)
127
-
128
- assert len(referenced) == n_items
129
-
130
- def test_on_item_update():
131
- """Test item resolvers."""
132
- indexer = _get_mock()
133
-
134
- # item on loan
135
- pid = "itemid-56"
136
- item = Item.get_record_by_pid(pid)
137
- ItemIndexer().index(item)
138
-
139
- referenced = _assert_origin(indexer, ITEM_PID_TYPE, pid)
140
-
141
- # should re-index loans
142
- n_loans = 2 # from test data, including pending
143
- _assert_contains(referenced, CIRCULATION_LOAN_PID_TYPE)
144
-
145
- # should re-index document
146
- n_documents = 1 # from test data
147
- _assert_contains(referenced, DOCUMENT_PID_TYPE)
148
-
149
- assert len(referenced) == n_loans + n_documents
150
-
151
- def test_on_location_update():
152
- """Test location resolvers."""
153
- indexer = _get_mock()
154
-
155
- pid = "locid-2"
156
- loc = Location.get_record_by_pid(pid)
157
- LocationIndexer().index(loc)
158
-
159
- referenced = _assert_origin(indexer, LOCATION_PID_TYPE, pid)
160
-
161
- # should re-index internal locations
162
- n_intlocs = 1 # from test data
163
- _assert_contains(referenced, INTERNAL_LOCATION_PID_TYPE)
164
-
165
- # should re-index internal items
166
- n_items = 1 # from test data
167
- _assert_contains(referenced, ITEM_PID_TYPE)
168
-
169
- assert len(referenced) == n_intlocs + n_items
170
-
171
- def test_on_patron_update():
172
- """Test patron resolvers."""
173
- indexer = _get_mock()
174
-
175
- pid = "2"
176
- patron = Patron.get_patron(pid)
177
- PatronIndexer().index(patron)
178
-
179
- referenced = _assert_origin(indexer, PATRON_PID_TYPE, pid)
180
-
181
- # should re-index loans
182
- n_loans = 3 # from test data
183
- _assert_contains(referenced, CIRCULATION_LOAN_PID_TYPE)
184
-
185
- # should re-index document request
186
- n_doc_req = 1 # from test data
187
- _assert_contains(referenced, DOCUMENT_REQUEST_PID_TYPE)
188
-
189
- # should re-index acq
190
- n_acq = 1 # from test data
191
- _assert_contains(referenced, ORDER_PID_TYPE)
192
-
193
- # should re-index ill
194
- n_ill = 3 # from test data
195
- _assert_contains(referenced, BORROWING_REQUEST_PID_TYPE)
196
-
197
- expected_total = n_loans + n_doc_req + n_acq + n_ill
198
- assert len(referenced) == expected_total
199
-
200
- test_on_document_update()
201
- test_on_eitem_update()
202
- test_on_internal_location_update()
203
- test_on_item_update()
204
- test_on_location_update()
205
- test_on_patron_update()
@@ -1,142 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- #
3
- # Copyright (C) 2019 CERN.
4
- #
5
- # invenio-app-ils is free software; you can redistribute it and/or modify it
6
- # under the terms of the MIT License; see LICENSE file for more details.
7
-
8
- """Test records relations."""
9
-
10
- import json
11
-
12
- from flask import url_for
13
- from invenio_db import db
14
-
15
- from invenio_app_ils.signals import record_viewed
16
- from tests.helpers import user_login, user_logout
17
-
18
-
19
- def _most_loaned_request(client, json_headers, from_date=None, to_date=None):
20
- """Perform a stats request."""
21
- params = []
22
- if from_date is not None:
23
- params.append("from_date={}".format(from_date))
24
- if to_date is not None:
25
- params.append("to_date={}".format(to_date))
26
- response = client.get(
27
- "{}?{}".format(
28
- url_for("invenio_app_ils_circulation_stats.most-loaned"),
29
- "&".join(params),
30
- ),
31
- headers=json_headers,
32
- )
33
- return json.loads(response.data.decode("utf-8"))
34
-
35
-
36
- def _assert_most_loaned(client, json_headers, from_date, to_date, expect):
37
- """Assert most loaned request."""
38
- resp = _most_loaned_request(client, json_headers, from_date, to_date)
39
- hits = resp["hits"]["hits"]
40
- assert len(hits) == len(expect)
41
- for hit in hits:
42
- pid = hit["metadata"]["pid"]
43
- assert hit["metadata"]["loan_count"] == expect[pid]["loans"]
44
- assert hit["metadata"]["loan_extensions"] == expect[pid]["extensions"]
45
-
46
-
47
- def test_stats_most_loaned_documents(client, json_headers, testdata_most_loaned, users):
48
- """Test most loaned documents API endpoint."""
49
- user_login(client, "librarian", users)
50
-
51
- # Dates covering all loans
52
- _assert_most_loaned(
53
- client,
54
- json_headers,
55
- "2019-01-01",
56
- "2019-12-01",
57
- expect={
58
- "docid-1": dict(loans=3, extensions=0),
59
- "docid-2": dict(loans=1, extensions=1),
60
- "docid-3": dict(loans=2, extensions=6),
61
- "docid-5": dict(loans=1, extensions=0),
62
- },
63
- )
64
- # Test checking range which should be empty
65
- _assert_most_loaned(client, json_headers, "2019-01-01", "2019-01-01", expect={})
66
- # Test range only including the first loan
67
- _assert_most_loaned(
68
- client,
69
- json_headers,
70
- "2019-01-01",
71
- "2019-01-03",
72
- expect={"docid-1": dict(loans=1, extensions=0)},
73
- )
74
- _assert_most_loaned(
75
- client,
76
- json_headers,
77
- "2019-02-02",
78
- "2019-03-02",
79
- expect={
80
- "docid-1": dict(loans=2, extensions=0),
81
- "docid-2": dict(loans=1, extensions=1),
82
- "docid-3": dict(loans=1, extensions=3),
83
- },
84
- )
85
- _assert_most_loaned(
86
- client,
87
- json_headers,
88
- "2019-05-20",
89
- "2019-08-22",
90
- expect={"docid-3": dict(loans=1, extensions=3)},
91
- )
92
- # outside end range
93
- _assert_most_loaned(client, json_headers, "2019-05-21", "2019-12-31", expect={})
94
-
95
-
96
- def test_stats_downloads_views_permissions(
97
- client, json_headers, users, testdata, mocker
98
- ):
99
- """Test permissions on downloads/views stats."""
100
-
101
- # mock record_viewed signal because travis timed out and the signal does
102
- # not need to be tested here
103
- mocker.patch(
104
- "invenio_app_ils.signals.record_viewed.send",
105
- )
106
-
107
- url_open_access = url_for(
108
- "ils_document_stats.docid_stats", pid_value="docid-open-access"
109
- )
110
- url_closed_access = url_for(
111
- "ils_document_stats.docid_stats", pid_value="docid-closed-access"
112
- )
113
- params = {}
114
- params["event"] = "record-view"
115
-
116
- # permission for librarian
117
- user_login(client, "librarian", users)
118
- res = client.post(url_open_access, headers=json_headers, data=json.dumps(params))
119
- assert res.status_code == 202
120
-
121
- res = client.post(url_closed_access, headers=json_headers, data=json.dumps(params))
122
- assert res.status_code == 202
123
-
124
- user_logout(client)
125
-
126
- # permission for patron
127
- user_login(client, "patron1", users)
128
-
129
- res = client.post(url_open_access, headers=json_headers, data=json.dumps(params))
130
- assert res.status_code == 202
131
-
132
- res = client.post(url_closed_access, headers=json_headers, data=json.dumps(params))
133
- assert res.status_code == 403
134
-
135
- user_logout(client)
136
-
137
- # permission for unauthenticated user
138
- res = client.post(url_open_access, headers=json_headers, data=json.dumps(params))
139
- assert res.status_code == 202
140
-
141
- res = client.post(url_closed_access, headers=json_headers, data=json.dumps(params))
142
- assert res.status_code == 401
@@ -1,209 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- #
3
- # Copyright (C) 2020 CERN.
4
- #
5
- # invenio-app-ils is free software; you can redistribute it and/or modify it
6
- # under the terms of the MIT License; see LICENSE file for more details.
7
-
8
- """Test location closure cronjobs."""
9
-
10
- import time
11
-
12
- import arrow
13
- from invenio_circulation.proxies import current_circulation
14
-
15
- from invenio_app_ils.circulation.search import get_active_loans
16
- from invenio_app_ils.closures.tasks import (
17
- clean_locations_past_closures_exceptions,
18
- extend_active_loans_location_closure,
19
- )
20
- from invenio_app_ils.proxies import current_app_ils
21
-
22
- _LOCATION_PID_1 = "locid-1"
23
- _LOCATION_PID_2 = "locid-2"
24
- _LOAN_PID_1 = "loanid-6"
25
- _LOAN_PID_2 = "loanid-5"
26
-
27
-
28
- _OPENING_EXCEPTIONS_WITH_PAST_EXCEPTIONS = [
29
- {
30
- "title": "Past holidays",
31
- "is_open": False,
32
- "start_date": "2010-01-01",
33
- "end_date": "2010-01-06",
34
- },
35
- {
36
- "title": "Past holidays",
37
- "is_open": False,
38
- "start_date": "2013-04-05",
39
- "end_date": "2013-04-08",
40
- },
41
- {
42
- "title": "Past holiday",
43
- "is_open": False,
44
- "start_date": "2005-05-14",
45
- "end_date": "2005-05-16",
46
- },
47
- {
48
- "title": "Past holidays",
49
- "is_open": False,
50
- "start_date": "2019-02-01",
51
- "end_date": "2019-02-06",
52
- },
53
- {
54
- "title": "Future holidays",
55
- "is_open": False,
56
- "start_date": "2100-02-11",
57
- "end_date": "2100-02-12",
58
- },
59
- {
60
- "title": "Future holidays",
61
- "is_open": False,
62
- "start_date": "2100-03-01",
63
- "end_date": "2100-03-06",
64
- },
65
- ]
66
-
67
- _OPENING_EXCEPTIONS_WITHOUT_CHANGES = [
68
- {
69
- "title": "Future holidays",
70
- "is_open": False,
71
- "start_date": "2110-01-01",
72
- "end_date": "2110-01-06",
73
- },
74
- {
75
- "title": "Future holidays",
76
- "is_open": False,
77
- "start_date": "2113-04-05",
78
- "end_date": "2113-04-08",
79
- },
80
- {
81
- "title": "Future holidays",
82
- "is_open": False,
83
- "start_date": "2105-05-14",
84
- "end_date": "2105-05-16",
85
- },
86
- {
87
- "title": "Future holidays",
88
- "is_open": False,
89
- "start_date": "2119-02-01",
90
- "end_date": "2119-02-06",
91
- },
92
- {
93
- "title": "Future holidays",
94
- "is_open": False,
95
- "start_date": "2100-02-11",
96
- "end_date": "2100-02-12",
97
- },
98
- {
99
- "title": "Future holidays",
100
- "is_open": False,
101
- "start_date": "2100-03-01",
102
- "end_date": "2100-03-06",
103
- },
104
- ]
105
-
106
-
107
- def prepare_data(db, location_pid, opening_exceptions):
108
- """Adds some opening exceptions to a concrete location."""
109
-
110
- location = current_app_ils.location_record_cls
111
- record = location.get_record_by_pid(location_pid)
112
-
113
- record.update({"opening_exceptions": opening_exceptions})
114
- record.commit()
115
- db.session.commit()
116
- current_app_ils.location_indexer.index(record)
117
-
118
-
119
- def prepare_loans_data(db, testdata):
120
- """Updates the expire date of a loan to match a closure day."""
121
- loans = testdata["loans"]
122
-
123
- def new_expiration_date(loan_test_data, date):
124
- loan = current_circulation.loan_record_cls.get_record_by_pid(
125
- loan_test_data["pid"]
126
- )
127
- loan.update(end_date=date.isoformat())
128
- loan.commit()
129
- db.session.commit()
130
- current_circulation.loan_indexer().index(loan)
131
-
132
- # Change expiration date to match closure
133
- date = arrow.get("2100-03-03").date()
134
- date_2 = arrow.get("2100-02-12").date()
135
- new_expiration_date(loans[5], date)
136
- new_expiration_date(loans[4], date_2)
137
-
138
-
139
- def opening_exceptions_cleaned():
140
- """Prepare data that should match with the response."""
141
- opening_exceptions = [
142
- {
143
- "title": "Future holidays",
144
- "is_open": False,
145
- "start_date": "2100-02-11",
146
- "end_date": "2100-02-12",
147
- },
148
- {
149
- "title": "Future holidays",
150
- "is_open": False,
151
- "start_date": "2100-03-01",
152
- "end_date": "2100-03-06",
153
- },
154
- ]
155
-
156
- return opening_exceptions
157
-
158
-
159
- def test_clean_locations_past_closures_exceptions(db, users, testdata):
160
- """Test cleaning of past exceptions."""
161
- prepare_data(db, _LOCATION_PID_1, _OPENING_EXCEPTIONS_WITH_PAST_EXCEPTIONS)
162
- prepare_data(db, _LOCATION_PID_2, _OPENING_EXCEPTIONS_WITH_PAST_EXCEPTIONS)
163
- clean_locations_past_closures_exceptions()
164
- location = current_app_ils.location_record_cls
165
- record = location.get_record_by_pid(_LOCATION_PID_1)
166
- record_2 = location.get_record_by_pid(_LOCATION_PID_2)
167
-
168
- assert record["opening_exceptions"] == opening_exceptions_cleaned()
169
- assert record_2["opening_exceptions"] == opening_exceptions_cleaned()
170
-
171
-
172
- def test_no_changes_on_loans(db, users, testdata):
173
- """Test that no changes are applied to the loans if not needed."""
174
- prepare_data(db, _LOCATION_PID_1, _OPENING_EXCEPTIONS_WITHOUT_CHANGES)
175
- loans = testdata["loans"]
176
- clean_locations_past_closures_exceptions()
177
- for hit in get_active_loans().scan():
178
- for loan in loans:
179
- if hit["pid"] == loan["pid"]:
180
- assert hit["end_date"] == loan["end_date"]
181
-
182
-
183
- def test_no_changes_on_exceptions(db, users, testdata):
184
- """Test that no changes are applied to the exceptions if not needed."""
185
- prepare_data(db, _LOCATION_PID_1, _OPENING_EXCEPTIONS_WITHOUT_CHANGES)
186
- extend_active_loans_location_closure(_LOCATION_PID_1)
187
- location = current_app_ils.location_record_cls
188
- record = location.get_record_by_pid(_LOCATION_PID_1)
189
- record_2 = location.get_record_by_pid(_LOCATION_PID_2)
190
-
191
- assert record["opening_exceptions"] == _OPENING_EXCEPTIONS_WITHOUT_CHANGES
192
- assert record_2["opening_exceptions"] == []
193
-
194
-
195
- def test_extend_active_loans_location_closure(db, users, testdata, app_with_notifs):
196
- """Test extension of active loans that finish on holidays."""
197
- prepare_data(db, _LOCATION_PID_1, _OPENING_EXCEPTIONS_WITH_PAST_EXCEPTIONS)
198
- prepare_loans_data(db, testdata)
199
- time.sleep(3)
200
-
201
- with app_with_notifs.extensions["mail"].record_messages() as outbox:
202
- assert len(outbox) == 0
203
- extend_active_loans_location_closure(_LOCATION_PID_1)
204
- assert len(outbox) == 2
205
-
206
- loan = current_circulation.loan_record_cls.get_record_by_pid(_LOAN_PID_1)
207
- loan_2 = current_circulation.loan_record_cls.get_record_by_pid(_LOAN_PID_2)
208
- assert loan["end_date"] == "2100-03-07"
209
- assert loan_2["end_date"] == "2100-02-13"