udata 14.0.0__py3-none-any.whl → 14.5.1.dev6__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.
Potentially problematic release.
This version of udata might be problematic. Click here for more details.
- udata/api/__init__.py +2 -0
- udata/api_fields.py +35 -4
- udata/app.py +18 -20
- udata/auth/__init__.py +29 -6
- udata/auth/forms.py +2 -2
- udata/auth/views.py +13 -6
- udata/commands/dcat.py +1 -1
- udata/commands/serve.py +3 -11
- udata/commands/tests/test_fixtures.py +9 -9
- udata/core/access_type/api.py +1 -1
- udata/core/access_type/constants.py +12 -8
- udata/core/activity/api.py +5 -6
- udata/core/badges/tests/test_commands.py +6 -6
- udata/core/csv.py +5 -0
- udata/core/dataservices/api.py +8 -1
- udata/core/dataservices/apiv2.py +2 -5
- udata/core/dataservices/models.py +5 -2
- udata/core/dataservices/rdf.py +2 -1
- udata/core/dataservices/tasks.py +13 -2
- udata/core/dataset/api.py +10 -0
- udata/core/dataset/models.py +6 -6
- udata/core/dataset/permissions.py +31 -0
- udata/core/dataset/rdf.py +8 -2
- udata/core/dataset/tasks.py +23 -7
- udata/core/discussions/api.py +15 -1
- udata/core/discussions/models.py +6 -0
- udata/core/legal/__init__.py +0 -0
- udata/core/legal/mails.py +128 -0
- udata/core/organization/api.py +16 -5
- udata/core/organization/apiv2.py +2 -3
- udata/core/organization/mails.py +1 -1
- udata/core/organization/models.py +15 -2
- udata/core/organization/notifications.py +84 -0
- udata/core/organization/permissions.py +1 -1
- udata/core/organization/tasks.py +3 -0
- udata/core/pages/tests/test_api.py +32 -0
- udata/core/post/api.py +24 -69
- udata/core/post/models.py +84 -16
- udata/core/post/tests/test_api.py +24 -1
- udata/core/reports/api.py +18 -0
- udata/core/reports/models.py +42 -2
- udata/core/reuse/api.py +8 -0
- udata/core/reuse/apiv2.py +2 -5
- udata/core/reuse/models.py +1 -1
- udata/core/reuse/tasks.py +7 -0
- udata/core/spatial/forms.py +2 -2
- udata/core/topic/models.py +8 -2
- udata/core/user/api.py +10 -3
- udata/core/user/models.py +12 -2
- udata/features/notifications/api.py +7 -18
- udata/features/notifications/models.py +56 -0
- udata/features/notifications/tasks.py +25 -0
- udata/flask_mongoengine/engine.py +0 -4
- udata/flask_mongoengine/pagination.py +1 -1
- udata/frontend/markdown.py +2 -1
- udata/harvest/actions.py +21 -1
- udata/harvest/api.py +25 -8
- udata/harvest/backends/base.py +27 -1
- udata/harvest/backends/ckan/harvesters.py +11 -2
- udata/harvest/backends/dcat.py +4 -1
- udata/harvest/commands.py +33 -0
- udata/harvest/filters.py +17 -6
- udata/harvest/models.py +16 -0
- udata/harvest/permissions.py +27 -0
- udata/harvest/tests/ckan/test_ckan_backend.py +33 -0
- udata/harvest/tests/test_actions.py +58 -5
- udata/harvest/tests/test_api.py +276 -122
- udata/harvest/tests/test_base_backend.py +86 -1
- udata/harvest/tests/test_dcat_backend.py +81 -10
- udata/harvest/tests/test_filters.py +6 -0
- udata/i18n.py +1 -4
- udata/mail.py +19 -1
- udata/migrations/2025-10-31-create-membership-request-notifications.py +55 -0
- udata/migrations/2025-12-04-add-uuid-to-discussion-messages.py +28 -0
- udata/mongo/slug_fields.py +1 -1
- udata/rdf.py +58 -10
- udata/routing.py +2 -2
- udata/settings.py +11 -0
- udata/tasks.py +1 -0
- udata/templates/mail/message.html +5 -31
- udata/tests/__init__.py +27 -2
- udata/tests/api/__init__.py +108 -21
- udata/tests/api/test_activities_api.py +36 -0
- udata/tests/api/test_auth_api.py +121 -95
- udata/tests/api/test_base_api.py +7 -4
- udata/tests/api/test_datasets_api.py +50 -19
- udata/tests/api/test_organizations_api.py +192 -197
- udata/tests/api/test_reports_api.py +157 -0
- udata/tests/api/test_reuses_api.py +147 -147
- udata/tests/api/test_security_api.py +12 -12
- udata/tests/api/test_swagger.py +4 -4
- udata/tests/api/test_tags_api.py +8 -8
- udata/tests/api/test_user_api.py +1 -1
- udata/tests/apiv2/test_search.py +30 -0
- udata/tests/apiv2/test_swagger.py +4 -4
- udata/tests/cli/test_cli_base.py +8 -9
- udata/tests/dataservice/test_dataservice_tasks.py +29 -0
- udata/tests/dataset/test_dataset_commands.py +4 -4
- udata/tests/dataset/test_dataset_model.py +66 -26
- udata/tests/dataset/test_dataset_rdf.py +99 -5
- udata/tests/dataset/test_dataset_tasks.py +25 -0
- udata/tests/frontend/test_auth.py +58 -1
- udata/tests/frontend/test_csv.py +0 -3
- udata/tests/helpers.py +31 -27
- udata/tests/organization/test_notifications.py +67 -2
- udata/tests/plugin.py +6 -261
- udata/tests/search/test_search_integration.py +33 -0
- udata/tests/site/test_site_csv_exports.py +22 -10
- udata/tests/test_activity.py +9 -9
- udata/tests/test_api_fields.py +10 -0
- udata/tests/test_dcat_commands.py +2 -2
- udata/tests/test_discussions.py +5 -5
- udata/tests/test_legal_mails.py +359 -0
- udata/tests/test_migrations.py +21 -21
- udata/tests/test_notifications.py +15 -57
- udata/tests/test_notifications_task.py +43 -0
- udata/tests/test_owned.py +81 -1
- udata/tests/test_storages.py +25 -19
- udata/tests/test_topics.py +77 -61
- udata/tests/test_uris.py +33 -0
- udata/tests/workers/test_jobs_commands.py +23 -23
- udata/translations/ar/LC_MESSAGES/udata.mo +0 -0
- udata/translations/ar/LC_MESSAGES/udata.po +187 -108
- udata/translations/de/LC_MESSAGES/udata.mo +0 -0
- udata/translations/de/LC_MESSAGES/udata.po +187 -108
- udata/translations/es/LC_MESSAGES/udata.mo +0 -0
- udata/translations/es/LC_MESSAGES/udata.po +187 -108
- udata/translations/fr/LC_MESSAGES/udata.mo +0 -0
- udata/translations/fr/LC_MESSAGES/udata.po +188 -109
- udata/translations/it/LC_MESSAGES/udata.mo +0 -0
- udata/translations/it/LC_MESSAGES/udata.po +187 -108
- udata/translations/pt/LC_MESSAGES/udata.mo +0 -0
- udata/translations/pt/LC_MESSAGES/udata.po +187 -108
- udata/translations/sr/LC_MESSAGES/udata.mo +0 -0
- udata/translations/sr/LC_MESSAGES/udata.po +187 -108
- udata/translations/udata.pot +215 -106
- udata/uris.py +0 -2
- udata-14.5.1.dev6.dist-info/METADATA +109 -0
- {udata-14.0.0.dist-info → udata-14.5.1.dev6.dist-info}/RECORD +143 -140
- udata/core/post/forms.py +0 -30
- udata/flask_mongoengine/json.py +0 -38
- udata/templates/mail/base.html +0 -105
- udata/templates/mail/base.txt +0 -6
- udata/templates/mail/button.html +0 -3
- udata/templates/mail/layouts/1-column.html +0 -19
- udata/templates/mail/layouts/2-columns.html +0 -20
- udata/templates/mail/layouts/center-panel.html +0 -16
- udata-14.0.0.dist-info/METADATA +0 -132
- {udata-14.0.0.dist-info → udata-14.5.1.dev6.dist-info}/WHEEL +0 -0
- {udata-14.0.0.dist-info → udata-14.5.1.dev6.dist-info}/entry_points.txt +0 -0
- {udata-14.0.0.dist-info → udata-14.5.1.dev6.dist-info}/licenses/LICENSE +0 -0
- {udata-14.0.0.dist-info → udata-14.5.1.dev6.dist-info}/top_level.txt +0 -0
udata/harvest/tests/test_api.py
CHANGED
|
@@ -5,13 +5,14 @@ import pytest
|
|
|
5
5
|
from flask import url_for
|
|
6
6
|
from pytest_mock import MockerFixture
|
|
7
7
|
|
|
8
|
+
from udata.core.dataservices.factories import DataserviceFactory
|
|
9
|
+
from udata.core.dataset.factories import DatasetFactory
|
|
8
10
|
from udata.core.organization.factories import OrganizationFactory
|
|
9
11
|
from udata.core.user.factories import AdminFactory, UserFactory
|
|
10
12
|
from udata.harvest.backends import get_enabled_backends
|
|
11
13
|
from udata.models import Member, PeriodicTask
|
|
12
14
|
from udata.tests.api import PytestOnlyAPITestCase
|
|
13
15
|
from udata.tests.helpers import assert200, assert201, assert204, assert400, assert403, assert404
|
|
14
|
-
from udata.tests.plugin import ApiClient
|
|
15
16
|
from udata.utils import faker
|
|
16
17
|
|
|
17
18
|
from .. import actions
|
|
@@ -19,18 +20,19 @@ from ..models import (
|
|
|
19
20
|
VALIDATION_ACCEPTED,
|
|
20
21
|
VALIDATION_PENDING,
|
|
21
22
|
VALIDATION_REFUSED,
|
|
23
|
+
HarvestItem,
|
|
22
24
|
HarvestSource,
|
|
23
25
|
HarvestSourceValidation,
|
|
24
26
|
)
|
|
25
|
-
from .factories import HarvestSourceFactory, MockBackendsMixin
|
|
27
|
+
from .factories import HarvestJobFactory, HarvestSourceFactory, MockBackendsMixin
|
|
26
28
|
|
|
27
29
|
log = logging.getLogger(__name__)
|
|
28
30
|
|
|
29
31
|
|
|
30
32
|
class HarvestAPITest(MockBackendsMixin, PytestOnlyAPITestCase):
|
|
31
|
-
def test_list_backends(self
|
|
33
|
+
def test_list_backends(self):
|
|
32
34
|
"""It should fetch the harvest backends list from the API"""
|
|
33
|
-
response =
|
|
35
|
+
response = self.get(url_for("api.harvest_backends"))
|
|
34
36
|
assert200(response)
|
|
35
37
|
assert len(response.json) == len(get_enabled_backends())
|
|
36
38
|
for data in response.json:
|
|
@@ -40,87 +42,87 @@ class HarvestAPITest(MockBackendsMixin, PytestOnlyAPITestCase):
|
|
|
40
42
|
assert isinstance(data["filters"], (list, tuple))
|
|
41
43
|
assert "extra_configs" in data
|
|
42
44
|
|
|
43
|
-
def test_list_sources(self
|
|
45
|
+
def test_list_sources(self):
|
|
44
46
|
sources = HarvestSourceFactory.create_batch(3)
|
|
45
47
|
|
|
46
|
-
response =
|
|
48
|
+
response = self.get(url_for("api.harvest_sources"))
|
|
47
49
|
assert200(response)
|
|
48
50
|
assert len(response.json["data"]) == len(sources)
|
|
49
51
|
|
|
50
|
-
def test_list_sources_exclude_deleted(self
|
|
52
|
+
def test_list_sources_exclude_deleted(self):
|
|
51
53
|
sources = HarvestSourceFactory.create_batch(3)
|
|
52
54
|
HarvestSourceFactory.create_batch(2, deleted=datetime.utcnow())
|
|
53
55
|
|
|
54
|
-
response =
|
|
56
|
+
response = self.get(url_for("api.harvest_sources"))
|
|
55
57
|
assert200(response)
|
|
56
58
|
assert len(response.json["data"]) == len(sources)
|
|
57
59
|
|
|
58
|
-
def test_list_sources_include_deleted(self
|
|
60
|
+
def test_list_sources_include_deleted(self):
|
|
59
61
|
sources = HarvestSourceFactory.create_batch(3)
|
|
60
62
|
sources.extend(HarvestSourceFactory.create_batch(2, deleted=datetime.utcnow()))
|
|
61
63
|
|
|
62
|
-
response =
|
|
64
|
+
response = self.get(url_for("api.harvest_sources", deleted=True))
|
|
63
65
|
assert200(response)
|
|
64
66
|
assert len(response.json["data"]) == len(sources)
|
|
65
67
|
|
|
66
|
-
def test_list_sources_for_owner(self
|
|
68
|
+
def test_list_sources_for_owner(self):
|
|
67
69
|
owner = UserFactory()
|
|
68
70
|
sources = HarvestSourceFactory.create_batch(3, owner=owner)
|
|
69
71
|
HarvestSourceFactory()
|
|
70
72
|
|
|
71
73
|
url = url_for("api.harvest_sources", owner=str(owner.id))
|
|
72
|
-
response =
|
|
74
|
+
response = self.get(url)
|
|
73
75
|
assert200(response)
|
|
74
76
|
|
|
75
77
|
assert len(response.json["data"]) == len(sources)
|
|
76
78
|
|
|
77
|
-
def test_list_sources_for_org(self
|
|
79
|
+
def test_list_sources_for_org(self):
|
|
78
80
|
org = OrganizationFactory()
|
|
79
81
|
sources = HarvestSourceFactory.create_batch(3, organization=org)
|
|
80
82
|
HarvestSourceFactory()
|
|
81
83
|
|
|
82
|
-
response =
|
|
84
|
+
response = self.get(url_for("api.harvest_sources", owner=str(org.id)))
|
|
83
85
|
assert200(response)
|
|
84
86
|
|
|
85
87
|
assert len(response.json["data"]) == len(sources)
|
|
86
88
|
|
|
87
|
-
def test_list_sources_search(self
|
|
89
|
+
def test_list_sources_search(self):
|
|
88
90
|
HarvestSourceFactory.create_batch(3)
|
|
89
91
|
source = HarvestSourceFactory(name="Moissonneur GeoNetwork de la ville de Rennes")
|
|
90
92
|
|
|
91
93
|
url = url_for("api.harvest_sources", q="geonetwork rennes")
|
|
92
|
-
response =
|
|
94
|
+
response = self.get(url)
|
|
93
95
|
assert200(response)
|
|
94
96
|
|
|
95
97
|
assert len(response.json["data"]) == 1
|
|
96
98
|
assert response.json["data"][0]["id"] == str(source.id)
|
|
97
99
|
|
|
98
|
-
def test_list_sources_paginate(self
|
|
100
|
+
def test_list_sources_paginate(self):
|
|
99
101
|
total = 25
|
|
100
102
|
page_size = 20
|
|
101
103
|
HarvestSourceFactory.create_batch(total)
|
|
102
104
|
|
|
103
105
|
url = url_for("api.harvest_sources", page=1, page_size=page_size)
|
|
104
|
-
response =
|
|
106
|
+
response = self.get(url)
|
|
105
107
|
assert200(response)
|
|
106
108
|
assert len(response.json["data"]) == page_size
|
|
107
109
|
assert response.json["total"] == total
|
|
108
110
|
|
|
109
111
|
url = url_for("api.harvest_sources", page=2, page_size=page_size)
|
|
110
|
-
response =
|
|
112
|
+
response = self.get(url)
|
|
111
113
|
assert200(response)
|
|
112
114
|
assert len(response.json["data"]) == total - page_size
|
|
113
115
|
assert response.json["total"] == total
|
|
114
116
|
|
|
115
117
|
url = url_for("api.harvest_sources", page=3, page_size=page_size)
|
|
116
|
-
response =
|
|
118
|
+
response = self.get(url)
|
|
117
119
|
assert404(response)
|
|
118
120
|
|
|
119
|
-
def test_create_source_with_owner(self
|
|
121
|
+
def test_create_source_with_owner(self):
|
|
120
122
|
"""It should create and attach a new source to an owner"""
|
|
121
|
-
user =
|
|
123
|
+
user = self.login()
|
|
122
124
|
data = {"name": faker.word(), "url": faker.url(), "backend": "factory"}
|
|
123
|
-
response =
|
|
125
|
+
response = self.post(url_for("api.harvest_sources"), data)
|
|
124
126
|
|
|
125
127
|
assert201(response)
|
|
126
128
|
|
|
@@ -129,9 +131,9 @@ class HarvestAPITest(MockBackendsMixin, PytestOnlyAPITestCase):
|
|
|
129
131
|
assert source["owner"]["id"] == str(user.id)
|
|
130
132
|
assert source["organization"] is None
|
|
131
133
|
|
|
132
|
-
def test_create_source_with_org(self
|
|
134
|
+
def test_create_source_with_org(self):
|
|
133
135
|
"""It should create and attach a new source to an organization"""
|
|
134
|
-
user =
|
|
136
|
+
user = self.login()
|
|
135
137
|
member = Member(user=user, role="admin")
|
|
136
138
|
org = OrganizationFactory(members=[member])
|
|
137
139
|
data = {
|
|
@@ -140,7 +142,7 @@ class HarvestAPITest(MockBackendsMixin, PytestOnlyAPITestCase):
|
|
|
140
142
|
"backend": "factory",
|
|
141
143
|
"organization": str(org.id),
|
|
142
144
|
}
|
|
143
|
-
response =
|
|
145
|
+
response = self.post(url_for("api.harvest_sources"), data)
|
|
144
146
|
|
|
145
147
|
assert201(response)
|
|
146
148
|
|
|
@@ -149,9 +151,9 @@ class HarvestAPITest(MockBackendsMixin, PytestOnlyAPITestCase):
|
|
|
149
151
|
assert source["owner"] is None
|
|
150
152
|
assert source["organization"]["id"] == str(org.id)
|
|
151
153
|
|
|
152
|
-
def test_create_source_with_org_not_member(self
|
|
154
|
+
def test_create_source_with_org_not_member(self):
|
|
153
155
|
"""It should create and attach a new source to an organization"""
|
|
154
|
-
user =
|
|
156
|
+
user = self.login()
|
|
155
157
|
member = Member(user=user, role="editor")
|
|
156
158
|
org = OrganizationFactory(members=[member])
|
|
157
159
|
data = {
|
|
@@ -160,13 +162,13 @@ class HarvestAPITest(MockBackendsMixin, PytestOnlyAPITestCase):
|
|
|
160
162
|
"backend": "factory",
|
|
161
163
|
"organization": str(org.id),
|
|
162
164
|
}
|
|
163
|
-
response =
|
|
165
|
+
response = self.post(url_for("api.harvest_sources"), data)
|
|
164
166
|
|
|
165
167
|
assert403(response)
|
|
166
168
|
|
|
167
|
-
def test_create_source_with_config(self
|
|
169
|
+
def test_create_source_with_config(self):
|
|
168
170
|
"""It should create a new source with configuration"""
|
|
169
|
-
|
|
171
|
+
self.login()
|
|
170
172
|
data = {
|
|
171
173
|
"name": faker.word(),
|
|
172
174
|
"url": faker.url(),
|
|
@@ -187,7 +189,7 @@ class HarvestAPITest(MockBackendsMixin, PytestOnlyAPITestCase):
|
|
|
187
189
|
],
|
|
188
190
|
},
|
|
189
191
|
}
|
|
190
|
-
response =
|
|
192
|
+
response = self.post(url_for("api.harvest_sources"), data)
|
|
191
193
|
|
|
192
194
|
assert201(response)
|
|
193
195
|
|
|
@@ -208,9 +210,9 @@ class HarvestAPITest(MockBackendsMixin, PytestOnlyAPITestCase):
|
|
|
208
210
|
],
|
|
209
211
|
}
|
|
210
212
|
|
|
211
|
-
def test_create_source_with_unknown_filter(self
|
|
213
|
+
def test_create_source_with_unknown_filter(self):
|
|
212
214
|
"""Can only use known filters in config"""
|
|
213
|
-
|
|
215
|
+
self.login()
|
|
214
216
|
data = {
|
|
215
217
|
"name": faker.word(),
|
|
216
218
|
"url": faker.url(),
|
|
@@ -221,13 +223,13 @@ class HarvestAPITest(MockBackendsMixin, PytestOnlyAPITestCase):
|
|
|
221
223
|
]
|
|
222
224
|
},
|
|
223
225
|
}
|
|
224
|
-
response =
|
|
226
|
+
response = self.post(url_for("api.harvest_sources"), data)
|
|
225
227
|
|
|
226
228
|
assert400(response)
|
|
227
229
|
|
|
228
|
-
def test_create_source_with_bad_filter_type(self
|
|
230
|
+
def test_create_source_with_bad_filter_type(self):
|
|
229
231
|
"""Can only use the xpected filter type"""
|
|
230
|
-
|
|
232
|
+
self.login()
|
|
231
233
|
data = {
|
|
232
234
|
"name": faker.word(),
|
|
233
235
|
"url": faker.url(),
|
|
@@ -238,13 +240,13 @@ class HarvestAPITest(MockBackendsMixin, PytestOnlyAPITestCase):
|
|
|
238
240
|
]
|
|
239
241
|
},
|
|
240
242
|
}
|
|
241
|
-
response =
|
|
243
|
+
response = self.post(url_for("api.harvest_sources"), data)
|
|
242
244
|
|
|
243
245
|
assert400(response)
|
|
244
246
|
|
|
245
|
-
def test_create_source_with_bad_filter_format(self
|
|
247
|
+
def test_create_source_with_bad_filter_format(self):
|
|
246
248
|
"""Filters should have the right format"""
|
|
247
|
-
|
|
249
|
+
self.login()
|
|
248
250
|
data = {
|
|
249
251
|
"name": faker.word(),
|
|
250
252
|
"url": faker.url(),
|
|
@@ -255,13 +257,13 @@ class HarvestAPITest(MockBackendsMixin, PytestOnlyAPITestCase):
|
|
|
255
257
|
]
|
|
256
258
|
},
|
|
257
259
|
}
|
|
258
|
-
response =
|
|
260
|
+
response = self.post(url_for("api.harvest_sources"), data)
|
|
259
261
|
|
|
260
262
|
assert400(response)
|
|
261
263
|
|
|
262
|
-
def test_create_source_with_unknown_extra_config(self
|
|
264
|
+
def test_create_source_with_unknown_extra_config(self):
|
|
263
265
|
"""Can only use known extra config in config"""
|
|
264
|
-
|
|
266
|
+
self.login()
|
|
265
267
|
data = {
|
|
266
268
|
"name": faker.word(),
|
|
267
269
|
"url": faker.url(),
|
|
@@ -272,13 +274,13 @@ class HarvestAPITest(MockBackendsMixin, PytestOnlyAPITestCase):
|
|
|
272
274
|
]
|
|
273
275
|
},
|
|
274
276
|
}
|
|
275
|
-
response =
|
|
277
|
+
response = self.post(url_for("api.harvest_sources"), data)
|
|
276
278
|
|
|
277
279
|
assert400(response)
|
|
278
280
|
|
|
279
|
-
def test_create_source_with_bad_extra_config_type(self
|
|
281
|
+
def test_create_source_with_bad_extra_config_type(self):
|
|
280
282
|
"""Can only use the expected extra config type"""
|
|
281
|
-
|
|
283
|
+
self.login()
|
|
282
284
|
data = {
|
|
283
285
|
"name": faker.word(),
|
|
284
286
|
"url": faker.url(),
|
|
@@ -289,13 +291,13 @@ class HarvestAPITest(MockBackendsMixin, PytestOnlyAPITestCase):
|
|
|
289
291
|
]
|
|
290
292
|
},
|
|
291
293
|
}
|
|
292
|
-
response =
|
|
294
|
+
response = self.post(url_for("api.harvest_sources"), data)
|
|
293
295
|
|
|
294
296
|
assert400(response)
|
|
295
297
|
|
|
296
|
-
def test_create_source_with_bad_extra_config_format(self
|
|
298
|
+
def test_create_source_with_bad_extra_config_format(self):
|
|
297
299
|
"""Extra config should have the right format"""
|
|
298
|
-
|
|
300
|
+
self.login()
|
|
299
301
|
data = {
|
|
300
302
|
"name": faker.word(),
|
|
301
303
|
"url": faker.url(),
|
|
@@ -306,13 +308,13 @@ class HarvestAPITest(MockBackendsMixin, PytestOnlyAPITestCase):
|
|
|
306
308
|
]
|
|
307
309
|
},
|
|
308
310
|
}
|
|
309
|
-
response =
|
|
311
|
+
response = self.post(url_for("api.harvest_sources"), data)
|
|
310
312
|
|
|
311
313
|
assert400(response)
|
|
312
314
|
|
|
313
|
-
def test_create_source_with_unknown_feature(self
|
|
315
|
+
def test_create_source_with_unknown_feature(self):
|
|
314
316
|
"""Can only use known features in config"""
|
|
315
|
-
|
|
317
|
+
self.login()
|
|
316
318
|
data = {
|
|
317
319
|
"name": faker.word(),
|
|
318
320
|
"url": faker.url(),
|
|
@@ -321,13 +323,13 @@ class HarvestAPITest(MockBackendsMixin, PytestOnlyAPITestCase):
|
|
|
321
323
|
"features": {"unknown": True},
|
|
322
324
|
},
|
|
323
325
|
}
|
|
324
|
-
response =
|
|
326
|
+
response = self.post(url_for("api.harvest_sources"), data)
|
|
325
327
|
|
|
326
328
|
assert400(response)
|
|
327
329
|
|
|
328
|
-
def test_create_source_with_false_feature(self
|
|
330
|
+
def test_create_source_with_false_feature(self):
|
|
329
331
|
"""It should handled negative values"""
|
|
330
|
-
|
|
332
|
+
self.login()
|
|
331
333
|
data = {
|
|
332
334
|
"name": faker.word(),
|
|
333
335
|
"url": faker.url(),
|
|
@@ -339,7 +341,7 @@ class HarvestAPITest(MockBackendsMixin, PytestOnlyAPITestCase):
|
|
|
339
341
|
}
|
|
340
342
|
},
|
|
341
343
|
}
|
|
342
|
-
response =
|
|
344
|
+
response = self.post(url_for("api.harvest_sources"), data)
|
|
343
345
|
|
|
344
346
|
assert201(response)
|
|
345
347
|
|
|
@@ -351,9 +353,9 @@ class HarvestAPITest(MockBackendsMixin, PytestOnlyAPITestCase):
|
|
|
351
353
|
}
|
|
352
354
|
}
|
|
353
355
|
|
|
354
|
-
def test_create_source_with_not_boolean_feature(self
|
|
356
|
+
def test_create_source_with_not_boolean_feature(self):
|
|
355
357
|
"""It should handled negative values"""
|
|
356
|
-
|
|
358
|
+
self.login()
|
|
357
359
|
data = {
|
|
358
360
|
"name": faker.word(),
|
|
359
361
|
"url": faker.url(),
|
|
@@ -364,28 +366,28 @@ class HarvestAPITest(MockBackendsMixin, PytestOnlyAPITestCase):
|
|
|
364
366
|
}
|
|
365
367
|
},
|
|
366
368
|
}
|
|
367
|
-
response =
|
|
369
|
+
response = self.post(url_for("api.harvest_sources"), data)
|
|
368
370
|
|
|
369
371
|
assert400(response)
|
|
370
372
|
|
|
371
|
-
def test_create_source_with_config_with_custom_key(self
|
|
372
|
-
|
|
373
|
+
def test_create_source_with_config_with_custom_key(self):
|
|
374
|
+
self.login()
|
|
373
375
|
data = {
|
|
374
376
|
"name": faker.word(),
|
|
375
377
|
"url": faker.url(),
|
|
376
378
|
"backend": "factory",
|
|
377
379
|
"config": {"custom": "value"},
|
|
378
380
|
}
|
|
379
|
-
response =
|
|
381
|
+
response = self.post(url_for("api.harvest_sources"), data)
|
|
380
382
|
|
|
381
383
|
assert201(response)
|
|
382
384
|
|
|
383
385
|
source = response.json
|
|
384
386
|
assert source["config"] == {"custom": "value"}
|
|
385
387
|
|
|
386
|
-
def test_update_source(self
|
|
387
|
-
"""It should update a source if owner or orga
|
|
388
|
-
user =
|
|
388
|
+
def test_update_source(self):
|
|
389
|
+
"""It should update a source if owner or orga admin"""
|
|
390
|
+
user = self.login()
|
|
389
391
|
source = HarvestSourceFactory(owner=user)
|
|
390
392
|
new_url = faker.url()
|
|
391
393
|
data = {
|
|
@@ -395,20 +397,20 @@ class HarvestAPITest(MockBackendsMixin, PytestOnlyAPITestCase):
|
|
|
395
397
|
"backend": "factory",
|
|
396
398
|
}
|
|
397
399
|
api_url = url_for("api.harvest_source", source=source)
|
|
398
|
-
response =
|
|
400
|
+
response = self.put(api_url, data)
|
|
399
401
|
assert200(response)
|
|
400
402
|
assert response.json["url"] == new_url
|
|
401
403
|
|
|
402
|
-
# Source is now owned by orga, with user as
|
|
403
|
-
source.organization = OrganizationFactory(members=[Member(user=user)])
|
|
404
|
+
# Source is now owned by orga, with user as admin
|
|
405
|
+
source.organization = OrganizationFactory(members=[Member(user=user, role="admin")])
|
|
404
406
|
source.save()
|
|
405
407
|
api_url = url_for("api.harvest_source", source=source)
|
|
406
|
-
response =
|
|
408
|
+
response = self.put(api_url, data)
|
|
407
409
|
assert200(response)
|
|
408
410
|
|
|
409
|
-
def test_update_source_require_permission(self
|
|
411
|
+
def test_update_source_require_permission(self):
|
|
410
412
|
"""It should not update a source if not the owner"""
|
|
411
|
-
|
|
413
|
+
self.login()
|
|
412
414
|
source = HarvestSourceFactory()
|
|
413
415
|
new_url: str = faker.url()
|
|
414
416
|
data = {
|
|
@@ -418,32 +420,32 @@ class HarvestAPITest(MockBackendsMixin, PytestOnlyAPITestCase):
|
|
|
418
420
|
"backend": "factory",
|
|
419
421
|
}
|
|
420
422
|
api_url: str = url_for("api.harvest_source", source=source)
|
|
421
|
-
response =
|
|
423
|
+
response = self.put(api_url, data)
|
|
422
424
|
|
|
423
425
|
assert403(response)
|
|
424
426
|
|
|
425
|
-
def test_validate_source(self
|
|
427
|
+
def test_validate_source(self):
|
|
426
428
|
"""It should allow to validate a source if admin"""
|
|
427
|
-
user =
|
|
429
|
+
user = self.login(AdminFactory())
|
|
428
430
|
source = HarvestSourceFactory()
|
|
429
431
|
|
|
430
432
|
data = {"state": VALIDATION_ACCEPTED}
|
|
431
433
|
url = url_for("api.validate_harvest_source", source=source)
|
|
432
|
-
response =
|
|
434
|
+
response = self.post(url, data)
|
|
433
435
|
assert200(response)
|
|
434
436
|
|
|
435
437
|
source.reload()
|
|
436
438
|
assert source.validation.state == VALIDATION_ACCEPTED
|
|
437
439
|
assert source.validation.by == user
|
|
438
440
|
|
|
439
|
-
def test_reject_source(self
|
|
441
|
+
def test_reject_source(self):
|
|
440
442
|
"""It should allow to reject a source if admin"""
|
|
441
|
-
user =
|
|
443
|
+
user = self.login(AdminFactory())
|
|
442
444
|
source = HarvestSourceFactory()
|
|
443
445
|
|
|
444
446
|
data = {"state": VALIDATION_REFUSED, "comment": "Not valid"}
|
|
445
447
|
url = url_for("api.validate_harvest_source", source=source)
|
|
446
|
-
response =
|
|
448
|
+
response = self.post(url, data)
|
|
447
449
|
assert200(response)
|
|
448
450
|
|
|
449
451
|
source.reload()
|
|
@@ -451,40 +453,40 @@ class HarvestAPITest(MockBackendsMixin, PytestOnlyAPITestCase):
|
|
|
451
453
|
assert source.validation.comment == "Not valid"
|
|
452
454
|
assert source.validation.by == user
|
|
453
455
|
|
|
454
|
-
def test_validate_source_is_admin_only(self
|
|
456
|
+
def test_validate_source_is_admin_only(self):
|
|
455
457
|
"""It should allow to validate a source if admin"""
|
|
456
|
-
|
|
458
|
+
self.login()
|
|
457
459
|
source = HarvestSourceFactory()
|
|
458
460
|
|
|
459
461
|
data = {"validate": True}
|
|
460
462
|
url = url_for("api.validate_harvest_source", source=source)
|
|
461
|
-
response =
|
|
463
|
+
response = self.post(url, data)
|
|
462
464
|
assert403(response)
|
|
463
465
|
|
|
464
|
-
def test_get_source(self
|
|
466
|
+
def test_get_source(self):
|
|
465
467
|
source = HarvestSourceFactory()
|
|
466
468
|
|
|
467
469
|
url = url_for("api.harvest_source", source=source)
|
|
468
|
-
response =
|
|
470
|
+
response = self.get(url)
|
|
469
471
|
assert200(response)
|
|
470
472
|
|
|
471
|
-
def test_get_missing_source(self
|
|
473
|
+
def test_get_missing_source(self):
|
|
472
474
|
url = url_for("api.harvest_source", source="685bb38b9cb9284b93fd9e72")
|
|
473
|
-
response =
|
|
475
|
+
response = self.get(url)
|
|
474
476
|
assert404(response)
|
|
475
477
|
|
|
476
|
-
def test_source_preview(self
|
|
477
|
-
|
|
478
|
-
source = HarvestSourceFactory(backend="factory")
|
|
478
|
+
def test_source_preview(self):
|
|
479
|
+
user = self.login()
|
|
480
|
+
source = HarvestSourceFactory(backend="factory", owner=user)
|
|
479
481
|
|
|
480
482
|
url = url_for("api.preview_harvest_source", source=source)
|
|
481
|
-
response =
|
|
483
|
+
response = self.get(url)
|
|
482
484
|
assert200(response)
|
|
483
485
|
|
|
484
486
|
@pytest.mark.options(HARVEST_ENABLE_MANUAL_RUN=True)
|
|
485
|
-
def test_run_source(self, mocker: MockerFixture
|
|
487
|
+
def test_run_source(self, mocker: MockerFixture):
|
|
486
488
|
launch = mocker.patch.object(actions.harvest, "delay")
|
|
487
|
-
user =
|
|
489
|
+
user = self.login()
|
|
488
490
|
|
|
489
491
|
source = HarvestSourceFactory(
|
|
490
492
|
backend="factory",
|
|
@@ -493,15 +495,15 @@ class HarvestAPITest(MockBackendsMixin, PytestOnlyAPITestCase):
|
|
|
493
495
|
)
|
|
494
496
|
|
|
495
497
|
url = url_for("api.run_harvest_source", source=source)
|
|
496
|
-
response =
|
|
498
|
+
response = self.post(url)
|
|
497
499
|
assert200(response)
|
|
498
500
|
|
|
499
501
|
launch.assert_called()
|
|
500
502
|
|
|
501
503
|
@pytest.mark.options(HARVEST_ENABLE_MANUAL_RUN=False)
|
|
502
|
-
def test_cannot_run_source_if_disabled(self, mocker: MockerFixture
|
|
504
|
+
def test_cannot_run_source_if_disabled(self, mocker: MockerFixture):
|
|
503
505
|
launch = mocker.patch.object(actions.harvest, "delay")
|
|
504
|
-
user =
|
|
506
|
+
user = self.login()
|
|
505
507
|
|
|
506
508
|
source = HarvestSourceFactory(
|
|
507
509
|
backend="factory",
|
|
@@ -510,16 +512,16 @@ class HarvestAPITest(MockBackendsMixin, PytestOnlyAPITestCase):
|
|
|
510
512
|
)
|
|
511
513
|
|
|
512
514
|
url = url_for("api.run_harvest_source", source=source)
|
|
513
|
-
response =
|
|
515
|
+
response = self.post(url)
|
|
514
516
|
assert400(response)
|
|
515
517
|
|
|
516
518
|
launch.assert_not_called()
|
|
517
519
|
|
|
518
520
|
@pytest.mark.options(HARVEST_ENABLE_MANUAL_RUN=True)
|
|
519
|
-
def test_cannot_run_source_if_not_owned(self, mocker: MockerFixture
|
|
521
|
+
def test_cannot_run_source_if_not_owned(self, mocker: MockerFixture):
|
|
520
522
|
launch = mocker.patch.object(actions.harvest, "delay")
|
|
521
523
|
other_user = UserFactory()
|
|
522
|
-
|
|
524
|
+
self.login()
|
|
523
525
|
|
|
524
526
|
source = HarvestSourceFactory(
|
|
525
527
|
backend="factory",
|
|
@@ -528,15 +530,15 @@ class HarvestAPITest(MockBackendsMixin, PytestOnlyAPITestCase):
|
|
|
528
530
|
)
|
|
529
531
|
|
|
530
532
|
url = url_for("api.run_harvest_source", source=source)
|
|
531
|
-
response =
|
|
533
|
+
response = self.post(url)
|
|
532
534
|
assert403(response)
|
|
533
535
|
|
|
534
536
|
launch.assert_not_called()
|
|
535
537
|
|
|
536
538
|
@pytest.mark.options(HARVEST_ENABLE_MANUAL_RUN=True)
|
|
537
|
-
def test_cannot_run_source_if_not_validated(self, mocker: MockerFixture
|
|
539
|
+
def test_cannot_run_source_if_not_validated(self, mocker: MockerFixture):
|
|
538
540
|
launch = mocker.patch.object(actions.harvest, "delay")
|
|
539
|
-
user =
|
|
541
|
+
user = self.login()
|
|
540
542
|
|
|
541
543
|
source = HarvestSourceFactory(
|
|
542
544
|
backend="factory",
|
|
@@ -545,46 +547,46 @@ class HarvestAPITest(MockBackendsMixin, PytestOnlyAPITestCase):
|
|
|
545
547
|
)
|
|
546
548
|
|
|
547
549
|
url = url_for("api.run_harvest_source", source=source)
|
|
548
|
-
response =
|
|
550
|
+
response = self.post(url)
|
|
549
551
|
assert400(response)
|
|
550
552
|
|
|
551
553
|
launch.assert_not_called()
|
|
552
554
|
|
|
553
|
-
def test_source_from_config(self
|
|
554
|
-
|
|
555
|
+
def test_source_from_config(self):
|
|
556
|
+
self.login()
|
|
555
557
|
data = {"name": faker.word(), "url": faker.url(), "backend": "factory"}
|
|
556
|
-
response =
|
|
558
|
+
response = self.post(url_for("api.preview_harvest_source_config"), data)
|
|
557
559
|
assert200(response)
|
|
558
560
|
|
|
559
|
-
def test_delete_source(self
|
|
560
|
-
user =
|
|
561
|
+
def test_delete_source(self):
|
|
562
|
+
user = self.login()
|
|
561
563
|
source = HarvestSourceFactory(owner=user)
|
|
562
564
|
|
|
563
565
|
url = url_for("api.harvest_source", source=source)
|
|
564
|
-
response =
|
|
566
|
+
response = self.delete(url)
|
|
565
567
|
assert204(response)
|
|
566
568
|
|
|
567
569
|
deleted_sources = HarvestSource.objects(deleted__exists=True)
|
|
568
570
|
assert len(deleted_sources) == 1
|
|
569
571
|
|
|
570
|
-
def test_delete_source_require_permission(self
|
|
572
|
+
def test_delete_source_require_permission(self):
|
|
571
573
|
"""It should not delete a source if not the owner"""
|
|
572
|
-
|
|
574
|
+
self.login()
|
|
573
575
|
source = HarvestSourceFactory()
|
|
574
576
|
|
|
575
577
|
url = url_for("api.harvest_source", source=source)
|
|
576
|
-
response =
|
|
578
|
+
response = self.delete(url)
|
|
577
579
|
|
|
578
580
|
assert403(response)
|
|
579
581
|
|
|
580
|
-
def test_schedule_source(self
|
|
582
|
+
def test_schedule_source(self):
|
|
581
583
|
"""It should allow to schedule a source if admin"""
|
|
582
|
-
|
|
584
|
+
self.login(AdminFactory())
|
|
583
585
|
source = HarvestSourceFactory()
|
|
584
586
|
|
|
585
587
|
data = "0 0 * * *"
|
|
586
588
|
url = url_for("api.schedule_harvest_source", source=source)
|
|
587
|
-
response =
|
|
589
|
+
response = self.post(url, data)
|
|
588
590
|
assert200(response)
|
|
589
591
|
|
|
590
592
|
assert response.json["schedule"] == "0 0 * * *"
|
|
@@ -599,22 +601,22 @@ class HarvestAPITest(MockBackendsMixin, PytestOnlyAPITestCase):
|
|
|
599
601
|
assert periodic_task.crontab.month_of_year == "*"
|
|
600
602
|
assert periodic_task.enabled
|
|
601
603
|
|
|
602
|
-
def test_schedule_source_is_admin_only(self
|
|
604
|
+
def test_schedule_source_is_admin_only(self):
|
|
603
605
|
"""It should only allow admins to schedule a source"""
|
|
604
|
-
|
|
606
|
+
self.login()
|
|
605
607
|
source = HarvestSourceFactory()
|
|
606
608
|
|
|
607
609
|
data = "0 0 * * *"
|
|
608
610
|
url = url_for("api.schedule_harvest_source", source=source)
|
|
609
|
-
response =
|
|
611
|
+
response = self.post(url, data)
|
|
610
612
|
assert403(response)
|
|
611
613
|
|
|
612
614
|
source.reload()
|
|
613
615
|
assert source.periodic_task is None
|
|
614
616
|
|
|
615
|
-
def test_unschedule_source(self
|
|
617
|
+
def test_unschedule_source(self):
|
|
616
618
|
"""It should allow to unschedule a source if admin"""
|
|
617
|
-
|
|
619
|
+
self.login(AdminFactory())
|
|
618
620
|
periodic_task = PeriodicTask.objects.create(
|
|
619
621
|
task="harvest",
|
|
620
622
|
name=faker.name(),
|
|
@@ -625,15 +627,15 @@ class HarvestAPITest(MockBackendsMixin, PytestOnlyAPITestCase):
|
|
|
625
627
|
source = HarvestSourceFactory(periodic_task=periodic_task)
|
|
626
628
|
|
|
627
629
|
url = url_for("api.schedule_harvest_source", source=source)
|
|
628
|
-
response =
|
|
630
|
+
response = self.delete(url)
|
|
629
631
|
assert204(response)
|
|
630
632
|
|
|
631
633
|
source.reload()
|
|
632
634
|
assert source.periodic_task is None
|
|
633
635
|
|
|
634
|
-
def test_unschedule_source_is_admin_only(self
|
|
636
|
+
def test_unschedule_source_is_admin_only(self):
|
|
635
637
|
"""It should only allow admins to unschedule a source"""
|
|
636
|
-
|
|
638
|
+
self.login()
|
|
637
639
|
periodic_task = PeriodicTask.objects.create(
|
|
638
640
|
task="harvest",
|
|
639
641
|
name=faker.name(),
|
|
@@ -644,8 +646,160 @@ class HarvestAPITest(MockBackendsMixin, PytestOnlyAPITestCase):
|
|
|
644
646
|
source = HarvestSourceFactory(periodic_task=periodic_task)
|
|
645
647
|
|
|
646
648
|
url = url_for("api.schedule_harvest_source", source=source)
|
|
647
|
-
response =
|
|
649
|
+
response = self.delete(url)
|
|
648
650
|
assert403(response)
|
|
649
651
|
|
|
650
652
|
source.reload()
|
|
651
653
|
assert source.periodic_task is not None
|
|
654
|
+
|
|
655
|
+
def test_list_items(self):
|
|
656
|
+
"""It should fetch the harvest items list from the API for a specific job"""
|
|
657
|
+
job = HarvestJobFactory(
|
|
658
|
+
items=[
|
|
659
|
+
HarvestItem(dataset=DatasetFactory()),
|
|
660
|
+
HarvestItem(dataservice=DataserviceFactory()),
|
|
661
|
+
HarvestItem(dataset=DatasetFactory(), remote_url="https://my.remote.example.com"),
|
|
662
|
+
],
|
|
663
|
+
)
|
|
664
|
+
response = self.get(url_for("api.harvest_job", ident=str(job.id)))
|
|
665
|
+
assert200(response)
|
|
666
|
+
assert len(response.json["items"]) == 3
|
|
667
|
+
assert set(response.json["items"][0].keys()) == set(
|
|
668
|
+
[
|
|
669
|
+
"created",
|
|
670
|
+
"started",
|
|
671
|
+
"ended",
|
|
672
|
+
"dataset",
|
|
673
|
+
"dataservice",
|
|
674
|
+
"remote_url",
|
|
675
|
+
"remote_id",
|
|
676
|
+
"args",
|
|
677
|
+
"errors",
|
|
678
|
+
"kwargs",
|
|
679
|
+
"logs",
|
|
680
|
+
"status",
|
|
681
|
+
]
|
|
682
|
+
)
|
|
683
|
+
# Make sure appropriate dataset or dataservice is set
|
|
684
|
+
assert response.json["items"][0]["dataset"] is not None
|
|
685
|
+
assert response.json["items"][0]["dataservice"] is None
|
|
686
|
+
assert response.json["items"][1]["dataset"] is None
|
|
687
|
+
assert response.json["items"][1]["dataservice"] is not None
|
|
688
|
+
# Make sure remote_url is exposed if exists
|
|
689
|
+
assert response.json["items"][1]["remote_url"] is None
|
|
690
|
+
assert response.json["items"][2]["remote_url"] == "https://my.remote.example.com"
|
|
691
|
+
|
|
692
|
+
def test_get_source_permissions_as_anonymous(self):
|
|
693
|
+
"""It should return all permissions as False for anonymous users"""
|
|
694
|
+
source = HarvestSourceFactory()
|
|
695
|
+
|
|
696
|
+
url = url_for("api.harvest_source", source=source)
|
|
697
|
+
response = self.get(url)
|
|
698
|
+
assert200(response)
|
|
699
|
+
|
|
700
|
+
assert "permissions" in response.json
|
|
701
|
+
permissions = response.json["permissions"]
|
|
702
|
+
assert permissions["edit"] is False
|
|
703
|
+
assert permissions["delete"] is False
|
|
704
|
+
assert permissions["run"] is False
|
|
705
|
+
assert permissions["preview"] is False
|
|
706
|
+
assert permissions["validate"] is False
|
|
707
|
+
assert permissions["schedule"] is False
|
|
708
|
+
|
|
709
|
+
def test_get_source_permissions_as_owner(self):
|
|
710
|
+
"""It should return owner permissions as True for source owner"""
|
|
711
|
+
user = self.login()
|
|
712
|
+
source = HarvestSourceFactory(owner=user)
|
|
713
|
+
|
|
714
|
+
url = url_for("api.harvest_source", source=source)
|
|
715
|
+
response = self.get(url)
|
|
716
|
+
assert200(response)
|
|
717
|
+
|
|
718
|
+
permissions = response.json["permissions"]
|
|
719
|
+
assert permissions["edit"] is True
|
|
720
|
+
assert permissions["delete"] is True
|
|
721
|
+
assert permissions["run"] is True
|
|
722
|
+
assert permissions["preview"] is True
|
|
723
|
+
assert permissions["validate"] is False
|
|
724
|
+
assert permissions["schedule"] is False
|
|
725
|
+
|
|
726
|
+
def test_get_source_permissions_as_org_admin(self):
|
|
727
|
+
"""It should return owner permissions as True for org admins"""
|
|
728
|
+
user = self.login()
|
|
729
|
+
member = Member(user=user, role="admin")
|
|
730
|
+
org = OrganizationFactory(members=[member])
|
|
731
|
+
source = HarvestSourceFactory(organization=org)
|
|
732
|
+
|
|
733
|
+
url = url_for("api.harvest_source", source=source)
|
|
734
|
+
response = self.get(url)
|
|
735
|
+
assert200(response)
|
|
736
|
+
|
|
737
|
+
permissions = response.json["permissions"]
|
|
738
|
+
assert permissions["edit"] is True
|
|
739
|
+
assert permissions["delete"] is True
|
|
740
|
+
assert permissions["run"] is True
|
|
741
|
+
assert permissions["preview"] is True
|
|
742
|
+
assert permissions["validate"] is False
|
|
743
|
+
assert permissions["schedule"] is False
|
|
744
|
+
|
|
745
|
+
def test_get_source_permissions_as_org_editor(self):
|
|
746
|
+
"""It should return only preview permission as True for org editors"""
|
|
747
|
+
user = self.login()
|
|
748
|
+
member = Member(user=user, role="editor")
|
|
749
|
+
org = OrganizationFactory(members=[member])
|
|
750
|
+
source = HarvestSourceFactory(organization=org)
|
|
751
|
+
|
|
752
|
+
url = url_for("api.harvest_source", source=source)
|
|
753
|
+
response = self.get(url)
|
|
754
|
+
assert200(response)
|
|
755
|
+
|
|
756
|
+
permissions = response.json["permissions"]
|
|
757
|
+
assert permissions["edit"] is False
|
|
758
|
+
assert permissions["delete"] is False
|
|
759
|
+
assert permissions["run"] is False
|
|
760
|
+
assert permissions["preview"] is True
|
|
761
|
+
assert permissions["validate"] is False
|
|
762
|
+
assert permissions["schedule"] is False
|
|
763
|
+
|
|
764
|
+
def test_get_source_permissions_as_superadmin(self):
|
|
765
|
+
"""It should return all permissions as True for admin users"""
|
|
766
|
+
self.login(AdminFactory())
|
|
767
|
+
source = HarvestSourceFactory()
|
|
768
|
+
|
|
769
|
+
url = url_for("api.harvest_source", source=source)
|
|
770
|
+
response = self.get(url)
|
|
771
|
+
assert200(response)
|
|
772
|
+
|
|
773
|
+
permissions = response.json["permissions"]
|
|
774
|
+
assert permissions["edit"] is True
|
|
775
|
+
assert permissions["delete"] is True
|
|
776
|
+
assert permissions["run"] is True
|
|
777
|
+
assert permissions["preview"] is True
|
|
778
|
+
assert permissions["validate"] is True
|
|
779
|
+
assert permissions["schedule"] is True
|
|
780
|
+
|
|
781
|
+
def test_get_source_permissions_as_other_user(self):
|
|
782
|
+
"""It should return all permissions as False for non-owner users"""
|
|
783
|
+
self.login()
|
|
784
|
+
source = HarvestSourceFactory() # owned by another user
|
|
785
|
+
|
|
786
|
+
url = url_for("api.harvest_source", source=source)
|
|
787
|
+
response = self.get(url)
|
|
788
|
+
assert200(response)
|
|
789
|
+
|
|
790
|
+
permissions = response.json["permissions"]
|
|
791
|
+
assert permissions["edit"] is False
|
|
792
|
+
assert permissions["delete"] is False
|
|
793
|
+
assert permissions["run"] is False
|
|
794
|
+
assert permissions["preview"] is False
|
|
795
|
+
assert permissions["validate"] is False
|
|
796
|
+
assert permissions["schedule"] is False
|
|
797
|
+
|
|
798
|
+
def test_preview_source_require_permission(self):
|
|
799
|
+
"""It should not allow preview if not the owner"""
|
|
800
|
+
self.login()
|
|
801
|
+
source = HarvestSourceFactory() # owned by another user
|
|
802
|
+
|
|
803
|
+
url = url_for("api.preview_harvest_source", source=source)
|
|
804
|
+
response = self.get(url)
|
|
805
|
+
assert403(response)
|