udata 12.0.2.dev10__py3-none-any.whl → 13.0.1.dev21__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.

Files changed (272) hide show
  1. udata/api/__init__.py +1 -0
  2. udata/api_fields.py +10 -4
  3. udata/app.py +11 -10
  4. udata/auth/__init__.py +9 -10
  5. udata/auth/mails.py +137 -45
  6. udata/auth/views.py +5 -12
  7. udata/commands/__init__.py +2 -4
  8. udata/commands/info.py +1 -3
  9. udata/commands/tests/test_fixtures.py +6 -3
  10. udata/core/access_type/api.py +18 -0
  11. udata/core/access_type/constants.py +98 -0
  12. udata/core/access_type/models.py +44 -0
  13. udata/core/activity/models.py +1 -1
  14. udata/core/badges/models.py +1 -1
  15. udata/core/badges/tasks.py +35 -1
  16. udata/core/badges/tests/test_commands.py +2 -4
  17. udata/core/badges/tests/test_model.py +2 -2
  18. udata/core/badges/tests/test_tasks.py +55 -0
  19. udata/core/constants.py +1 -0
  20. udata/core/contact_point/models.py +8 -0
  21. udata/core/dataservices/api.py +10 -12
  22. udata/core/dataservices/apiv2.py +3 -1
  23. udata/core/dataservices/constants.py +0 -29
  24. udata/core/dataservices/models.py +44 -44
  25. udata/core/dataservices/rdf.py +2 -1
  26. udata/core/dataservices/search.py +5 -9
  27. udata/core/dataservices/tasks.py +33 -0
  28. udata/core/dataset/api.py +15 -24
  29. udata/core/dataset/api_fields.py +11 -0
  30. udata/core/dataset/apiv2.py +11 -0
  31. udata/core/dataset/constants.py +0 -1
  32. udata/core/dataset/forms.py +29 -0
  33. udata/core/dataset/models.py +24 -42
  34. udata/core/dataset/rdf.py +2 -1
  35. udata/core/dataset/search.py +2 -2
  36. udata/core/dataset/tasks.py +86 -8
  37. udata/core/discussions/mails.py +63 -0
  38. udata/core/discussions/tasks.py +4 -18
  39. udata/core/metrics/__init__.py +0 -6
  40. udata/core/organization/api.py +20 -14
  41. udata/core/organization/mails.py +144 -0
  42. udata/core/organization/models.py +2 -1
  43. udata/core/organization/rdf.py +3 -3
  44. udata/core/organization/search.py +1 -1
  45. udata/core/organization/tasks.py +21 -49
  46. udata/core/pages/tests/test_api.py +0 -2
  47. udata/core/reuse/api.py +29 -3
  48. udata/core/reuse/mails.py +21 -0
  49. udata/core/reuse/models.py +10 -1
  50. udata/core/reuse/search.py +1 -1
  51. udata/core/reuse/tasks.py +2 -3
  52. udata/core/site/api.py +27 -19
  53. udata/core/site/models.py +2 -6
  54. udata/core/site/rdf.py +2 -2
  55. udata/core/spatial/tests/test_api.py +17 -20
  56. udata/core/spatial/tests/test_models.py +3 -3
  57. udata/core/user/mails.py +54 -0
  58. udata/core/user/models.py +2 -3
  59. udata/core/user/tasks.py +8 -23
  60. udata/core/user/tests/test_user_model.py +2 -6
  61. udata/entrypoints.py +0 -6
  62. udata/features/identicon/tests/test_backends.py +3 -13
  63. udata/forms/fields.py +3 -3
  64. udata/forms/widgets.py +2 -2
  65. udata/frontend/__init__.py +3 -32
  66. udata/harvest/actions.py +4 -9
  67. udata/harvest/api.py +5 -14
  68. udata/harvest/backends/__init__.py +20 -11
  69. udata/harvest/backends/base.py +2 -2
  70. udata/harvest/backends/ckan/harvesters.py +2 -1
  71. udata/harvest/backends/dcat.py +3 -0
  72. udata/harvest/backends/maaf.py +1 -0
  73. udata/harvest/commands.py +6 -4
  74. udata/harvest/forms.py +9 -6
  75. udata/harvest/tasks.py +3 -5
  76. udata/harvest/tests/ckan/test_ckan_backend.py +300 -337
  77. udata/harvest/tests/ckan/test_ckan_backend_errors.py +94 -99
  78. udata/harvest/tests/ckan/test_ckan_backend_filters.py +128 -122
  79. udata/harvest/tests/ckan/test_dkan_backend.py +39 -51
  80. udata/harvest/tests/dcat/bnodes.xml +17 -1
  81. udata/harvest/tests/dcat/datara--5a26b0f6-0ccf-46ad-ac58-734054b91977.rdf.xml +255 -0
  82. udata/harvest/tests/dcat/datara--f40c3860-7236-4b30-a141-23b8ae33f7b2.rdf.xml +289 -0
  83. udata/harvest/tests/factories.py +1 -1
  84. udata/harvest/tests/test_actions.py +11 -9
  85. udata/harvest/tests/test_api.py +4 -5
  86. udata/harvest/tests/test_base_backend.py +5 -4
  87. udata/harvest/tests/test_dcat_backend.py +72 -16
  88. udata/harvest/tests/test_models.py +2 -4
  89. udata/harvest/tests/test_notifications.py +2 -4
  90. udata/harvest/tests/test_tasks.py +2 -3
  91. udata/mail.py +90 -53
  92. udata/migrations/2025-01-05-dataservices-fields-changes.py +8 -14
  93. udata/migrations/2025-10-21-remove-ckan-harvest-modified-at.py +28 -0
  94. udata/migrations/2025-10-29-harvesters-sources-integrity.py +27 -0
  95. udata/models/__init__.py +0 -2
  96. udata/mongo/extras_fields.py +4 -3
  97. udata/mongo/taglist_field.py +3 -3
  98. udata/rdf.py +65 -20
  99. udata/sentry.py +3 -4
  100. udata/settings.py +15 -13
  101. udata/tags.py +5 -5
  102. udata/tasks.py +3 -3
  103. udata/templates/mail/message.html +65 -0
  104. udata/templates/mail/message.txt +16 -0
  105. udata/tests/__init__.py +40 -58
  106. udata/tests/api/__init__.py +87 -2
  107. udata/tests/api/test_activities_api.py +17 -23
  108. udata/tests/api/test_auth_api.py +2 -4
  109. udata/tests/api/test_contact_points.py +48 -54
  110. udata/tests/api/test_dataservices_api.py +65 -97
  111. udata/tests/api/test_datasets_api.py +171 -56
  112. udata/tests/api/test_me_api.py +4 -6
  113. udata/tests/api/test_organizations_api.py +19 -38
  114. udata/tests/api/test_reports_api.py +0 -4
  115. udata/tests/api/test_reuses_api.py +99 -23
  116. udata/tests/api/test_security_api.py +124 -0
  117. udata/tests/api/test_swagger.py +2 -3
  118. udata/tests/api/test_tags_api.py +6 -7
  119. udata/tests/api/test_transfer_api.py +0 -2
  120. udata/tests/api/test_user_api.py +8 -10
  121. udata/tests/apiv2/test_datasets.py +0 -4
  122. udata/tests/apiv2/test_me_api.py +0 -2
  123. udata/tests/apiv2/test_organizations.py +0 -2
  124. udata/tests/apiv2/test_swagger.py +2 -3
  125. udata/tests/apiv2/test_topics.py +0 -2
  126. udata/tests/cli/test_cli_base.py +14 -12
  127. udata/tests/cli/test_db_cli.py +51 -54
  128. udata/tests/contact_point/test_contact_point_models.py +2 -2
  129. udata/tests/dataservice/test_csv_adapter.py +2 -5
  130. udata/tests/dataservice/test_dataservice_rdf.py +64 -4
  131. udata/tests/dataservice/test_dataservice_tasks.py +36 -38
  132. udata/tests/dataset/test_csv_adapter.py +2 -5
  133. udata/tests/dataset/test_dataset_actions.py +2 -4
  134. udata/tests/dataset/test_dataset_commands.py +2 -4
  135. udata/tests/dataset/test_dataset_events.py +3 -3
  136. udata/tests/dataset/test_dataset_model.py +6 -7
  137. udata/tests/dataset/test_dataset_rdf.py +205 -16
  138. udata/tests/dataset/test_dataset_recommendations.py +2 -2
  139. udata/tests/dataset/test_dataset_tasks.py +66 -68
  140. udata/tests/dataset/test_resource_preview.py +39 -48
  141. udata/tests/dataset/test_transport_tasks.py +2 -2
  142. udata/tests/features/territories/__init__.py +0 -6
  143. udata/tests/features/territories/test_territories_api.py +25 -24
  144. udata/tests/forms/test_current_user_field.py +2 -2
  145. udata/tests/forms/test_dict_field.py +2 -4
  146. udata/tests/forms/test_extras_fields.py +2 -3
  147. udata/tests/forms/test_image_field.py +2 -2
  148. udata/tests/forms/test_model_field.py +2 -4
  149. udata/tests/forms/test_publish_as_field.py +2 -4
  150. udata/tests/forms/test_user_forms.py +26 -29
  151. udata/tests/frontend/test_auth.py +2 -3
  152. udata/tests/frontend/test_csv.py +5 -6
  153. udata/tests/frontend/test_error_handlers.py +2 -3
  154. udata/tests/frontend/test_hooks.py +5 -7
  155. udata/tests/frontend/test_markdown.py +3 -4
  156. udata/tests/helpers.py +2 -7
  157. udata/tests/metrics/test_metrics.py +52 -48
  158. udata/tests/metrics/test_tasks.py +154 -150
  159. udata/tests/organization/test_csv_adapter.py +2 -5
  160. udata/tests/organization/test_notifications.py +2 -4
  161. udata/tests/organization/test_organization_model.py +3 -4
  162. udata/tests/organization/test_organization_rdf.py +6 -12
  163. udata/tests/plugin.py +6 -110
  164. udata/tests/reuse/test_reuse_model.py +3 -4
  165. udata/tests/site/test_site_api.py +0 -2
  166. udata/tests/site/test_site_csv_exports.py +0 -2
  167. udata/tests/site/test_site_metrics.py +2 -4
  168. udata/tests/site/test_site_model.py +2 -2
  169. udata/tests/site/test_site_rdf.py +85 -29
  170. udata/tests/test_activity.py +3 -3
  171. udata/tests/test_api_fields.py +6 -9
  172. udata/tests/test_cors.py +0 -2
  173. udata/tests/test_dcat_commands.py +2 -3
  174. udata/tests/test_discussions.py +2 -7
  175. udata/tests/test_mail.py +150 -114
  176. udata/tests/test_migrations.py +413 -419
  177. udata/tests/test_model.py +10 -11
  178. udata/tests/test_notifications.py +2 -3
  179. udata/tests/test_owned.py +3 -3
  180. udata/tests/test_rdf.py +19 -15
  181. udata/tests/test_routing.py +5 -5
  182. udata/tests/test_storages.py +6 -5
  183. udata/tests/test_tags.py +2 -4
  184. udata/tests/test_topics.py +2 -4
  185. udata/tests/test_transfer.py +4 -5
  186. udata/tests/topic/test_topic_tasks.py +25 -27
  187. udata/tests/user/test_user_rdf.py +2 -8
  188. udata/tests/user/test_user_tasks.py +3 -5
  189. udata/tests/workers/test_jobs_commands.py +2 -2
  190. udata/tests/workers/test_tasks_routing.py +27 -27
  191. udata/translations/ar/LC_MESSAGES/udata.mo +0 -0
  192. udata/translations/ar/LC_MESSAGES/udata.po +369 -435
  193. udata/translations/de/LC_MESSAGES/udata.mo +0 -0
  194. udata/translations/de/LC_MESSAGES/udata.po +371 -437
  195. udata/translations/es/LC_MESSAGES/udata.mo +0 -0
  196. udata/translations/es/LC_MESSAGES/udata.po +369 -435
  197. udata/translations/fr/LC_MESSAGES/udata.mo +0 -0
  198. udata/translations/fr/LC_MESSAGES/udata.po +381 -447
  199. udata/translations/it/LC_MESSAGES/udata.mo +0 -0
  200. udata/translations/it/LC_MESSAGES/udata.po +371 -437
  201. udata/translations/pt/LC_MESSAGES/udata.mo +0 -0
  202. udata/translations/pt/LC_MESSAGES/udata.po +371 -437
  203. udata/translations/sr/LC_MESSAGES/udata.mo +0 -0
  204. udata/translations/sr/LC_MESSAGES/udata.po +372 -438
  205. udata/translations/udata.pot +379 -440
  206. udata/utils.py +66 -4
  207. {udata-12.0.2.dev10.dist-info → udata-13.0.1.dev21.dist-info}/METADATA +1 -4
  208. {udata-12.0.2.dev10.dist-info → udata-13.0.1.dev21.dist-info}/RECORD +212 -256
  209. udata/linkchecker/__init__.py +0 -0
  210. udata/linkchecker/backends.py +0 -31
  211. udata/linkchecker/checker.py +0 -75
  212. udata/linkchecker/commands.py +0 -21
  213. udata/linkchecker/models.py +0 -9
  214. udata/linkchecker/tasks.py +0 -55
  215. udata/templates/mail/account_deleted.html +0 -5
  216. udata/templates/mail/account_deleted.txt +0 -6
  217. udata/templates/mail/account_inactivity.html +0 -40
  218. udata/templates/mail/account_inactivity.txt +0 -31
  219. udata/templates/mail/badge_added_association.html +0 -33
  220. udata/templates/mail/badge_added_association.txt +0 -11
  221. udata/templates/mail/badge_added_certified.html +0 -33
  222. udata/templates/mail/badge_added_certified.txt +0 -11
  223. udata/templates/mail/badge_added_company.html +0 -33
  224. udata/templates/mail/badge_added_company.txt +0 -11
  225. udata/templates/mail/badge_added_local_authority.html +0 -33
  226. udata/templates/mail/badge_added_local_authority.txt +0 -11
  227. udata/templates/mail/badge_added_public_service.html +0 -33
  228. udata/templates/mail/badge_added_public_service.txt +0 -11
  229. udata/templates/mail/discussion_closed.html +0 -47
  230. udata/templates/mail/discussion_closed.txt +0 -16
  231. udata/templates/mail/inactive_account_deleted.html +0 -5
  232. udata/templates/mail/inactive_account_deleted.txt +0 -6
  233. udata/templates/mail/membership_refused.html +0 -20
  234. udata/templates/mail/membership_refused.txt +0 -11
  235. udata/templates/mail/membership_request.html +0 -46
  236. udata/templates/mail/membership_request.txt +0 -12
  237. udata/templates/mail/new_discussion.html +0 -44
  238. udata/templates/mail/new_discussion.txt +0 -15
  239. udata/templates/mail/new_discussion_comment.html +0 -45
  240. udata/templates/mail/new_discussion_comment.txt +0 -16
  241. udata/templates/mail/new_member.html +0 -27
  242. udata/templates/mail/new_member.txt +0 -11
  243. udata/templates/mail/new_reuse.html +0 -37
  244. udata/templates/mail/new_reuse.txt +0 -9
  245. udata/templates/mail/test.html +0 -6
  246. udata/templates/mail/test.txt +0 -6
  247. udata/templates/mail/user_mail_card.html +0 -26
  248. udata/templates/security/email/base.html +0 -105
  249. udata/templates/security/email/base.txt +0 -6
  250. udata/templates/security/email/button.html +0 -3
  251. udata/templates/security/email/change_notice.html +0 -22
  252. udata/templates/security/email/change_notice.txt +0 -8
  253. udata/templates/security/email/confirmation_instructions.html +0 -20
  254. udata/templates/security/email/confirmation_instructions.txt +0 -7
  255. udata/templates/security/email/login_instructions.html +0 -19
  256. udata/templates/security/email/login_instructions.txt +0 -7
  257. udata/templates/security/email/reset_instructions.html +0 -24
  258. udata/templates/security/email/reset_instructions.txt +0 -9
  259. udata/templates/security/email/reset_notice.html +0 -11
  260. udata/templates/security/email/reset_notice.txt +0 -4
  261. udata/templates/security/email/welcome.html +0 -24
  262. udata/templates/security/email/welcome.txt +0 -9
  263. udata/templates/security/email/welcome_existing.html +0 -32
  264. udata/templates/security/email/welcome_existing.txt +0 -14
  265. udata/terms.md +0 -6
  266. udata/tests/frontend/__init__.py +0 -23
  267. udata/tests/metrics/conftest.py +0 -15
  268. udata/tests/test_linkchecker.py +0 -277
  269. {udata-12.0.2.dev10.dist-info → udata-13.0.1.dev21.dist-info}/WHEEL +0 -0
  270. {udata-12.0.2.dev10.dist-info → udata-13.0.1.dev21.dist-info}/entry_points.txt +0 -0
  271. {udata-12.0.2.dev10.dist-info → udata-13.0.1.dev21.dist-info}/licenses/LICENSE +0 -0
  272. {udata-12.0.2.dev10.dist-info → udata-13.0.1.dev21.dist-info}/top_level.txt +0 -0
@@ -5,10 +5,10 @@ from flask import current_app, g
5
5
  from udata.core.dataset.factories import DatasetFactory
6
6
  from udata.core.reuse.factories import ReuseFactory
7
7
  from udata.core.site.models import Site, current_site, get_current_site
8
- from udata.tests import DBTestMixin, TestCase
8
+ from udata.tests.api import DBTestCase
9
9
 
10
10
 
11
- class SiteModelTest(DBTestMixin, TestCase):
11
+ class SiteModelTest(DBTestCase):
12
12
  def test_current_site(self):
13
13
  current_app.config["SITE_ID"] = "old-id"
14
14
  current_app.config["SITE_TITLE"] = "Test"
@@ -3,7 +3,9 @@ from flask import url_for
3
3
  from rdflib import Graph, Literal, URIRef
4
4
  from rdflib.namespace import FOAF, RDF
5
5
  from rdflib.resource import Resource
6
+ from werkzeug.datastructures import ImmutableMultiDict
6
7
 
8
+ from udata.core.constants import HVD
7
9
  from udata.core.dataservices.factories import DataserviceFactory, HarvestMetadataFactory
8
10
  from udata.core.dataset.factories import DatasetFactory
9
11
  from udata.core.dataset.models import Dataset
@@ -12,13 +14,11 @@ from udata.core.site.factories import SiteFactory
12
14
  from udata.core.site.rdf import build_catalog
13
15
  from udata.core.user.factories import UserFactory
14
16
  from udata.rdf import CONTEXT, DCAT, DCT, HYDRA
17
+ from udata.tests.api import PytestOnlyAPITestCase
15
18
  from udata.tests.helpers import assert200, assert404, assert_redirects
16
19
 
17
- pytestmark = pytest.mark.usefixtures("clean_db")
18
20
 
19
-
20
- @pytest.mark.frontend
21
- class CatalogTest:
21
+ class CatalogTest(PytestOnlyAPITestCase):
22
22
  def test_minimal(self, app):
23
23
  site = SiteFactory()
24
24
  home_url = url_for("api.site", _external=True)
@@ -77,14 +77,14 @@ class CatalogTest:
77
77
  uri = url_for("api.site_rdf_catalog", _external=True)
78
78
  uri_first = url_for(
79
79
  "api.site_rdf_catalog_format",
80
- format="json",
80
+ _format="json",
81
81
  page=1,
82
82
  page_size=page_size,
83
83
  _external=True,
84
84
  )
85
85
  uri_last = url_for(
86
86
  "api.site_rdf_catalog_format",
87
- format="json",
87
+ _format="json",
88
88
  page=2,
89
89
  page_size=page_size,
90
90
  _external=True,
@@ -93,7 +93,7 @@ class CatalogTest:
93
93
 
94
94
  # First page
95
95
  datasets = Dataset.objects.paginate(1, page_size)
96
- catalog = build_catalog(site, datasets, format="json")
96
+ catalog = build_catalog(site, datasets, _format="json")
97
97
  graph = catalog.graph
98
98
 
99
99
  assert isinstance(catalog, Resource)
@@ -117,7 +117,7 @@ class CatalogTest:
117
117
 
118
118
  # Second page
119
119
  datasets = Dataset.objects.paginate(2, page_size)
120
- catalog = build_catalog(site, datasets, format="json")
120
+ catalog = build_catalog(site, datasets, _format="json")
121
121
  graph = catalog.graph
122
122
 
123
123
  assert isinstance(catalog, Resource)
@@ -140,8 +140,7 @@ class CatalogTest:
140
140
  assert HYDRA.next not in pagination
141
141
 
142
142
 
143
- @pytest.mark.frontend
144
- class SiteRdfViewsTest:
143
+ class SiteRdfViewsTest(PytestOnlyAPITestCase):
145
144
  def test_expose_jsonld_context(self, client):
146
145
  url = url_for("api.site_jsonld_context")
147
146
  assert url == "/api/1/site/context.jsonld"
@@ -152,12 +151,39 @@ class SiteRdfViewsTest:
152
151
  assert response.json == CONTEXT
153
152
 
154
153
  def test_catalog_default_to_jsonld(self, client):
155
- expected = url_for("api.site_rdf_catalog_format", format="json")
154
+ expected = url_for("api.site_rdf_catalog_format", _format="json", page=1, page_size=100)
156
155
  response = client.get(url_for("api.site_rdf_catalog"))
157
156
  assert_redirects(response, expected)
158
157
 
158
+ def test_catalog_redirect_with_filters_sanitizing(self, client):
159
+ """
160
+ It should filter out unknown params (including url_for keywords).
161
+ Repeated keywords should be kept as expected.
162
+ """
163
+ expected_params = ImmutableMultiDict(
164
+ [("page", 3), ("tag", "hvd"), ("tag", "other"), ("page_size", 100)]
165
+ )
166
+ expected = url_for(
167
+ "api.site_rdf_catalog_format", _format="xml", **expected_params.to_dict(flat=False)
168
+ )
169
+ params = [
170
+ ("page", 3),
171
+ ("tag", "hvd"),
172
+ ("tag", "other"),
173
+ ("unknown_param", 5),
174
+ ("_external", True),
175
+ ]
176
+ url = (
177
+ url_for("api.site_rdf_catalog")
178
+ + "?"
179
+ + "&".join(f"{arg}={value}" for arg, value in params)
180
+ )
181
+ headers = {"accept": "application/xml"}
182
+ response = client.get(url, headers=headers)
183
+ assert_redirects(response, expected)
184
+
159
185
  def test_rdf_perform_content_negociation(self, client):
160
- expected = url_for("api.site_rdf_catalog_format", format="xml")
186
+ expected = url_for("api.site_rdf_catalog_format", _format="xml", page=1, page_size=100)
161
187
  url = url_for("api.site_rdf_catalog")
162
188
  headers = {"accept": "application/xml"}
163
189
  response = client.get(url, headers=headers)
@@ -165,57 +191,65 @@ class SiteRdfViewsTest:
165
191
 
166
192
  @pytest.mark.parametrize("fmt", ("json", "jsonld"))
167
193
  def test_catalog_rdf_json_ld(self, fmt, client):
168
- url = url_for("api.site_rdf_catalog_format", format=fmt)
194
+ url = url_for("api.site_rdf_catalog_format", _format=fmt)
169
195
  response = client.get(url, headers={"Accept": "application/ld+json"})
170
196
  assert200(response)
171
197
  assert response.content_type == "application/ld+json"
172
198
  assert response.json["@context"]["@vocab"] == "http://www.w3.org/ns/dcat#"
173
199
 
174
200
  def test_catalog_rdf_n3(self, client):
175
- url = url_for("api.site_rdf_catalog_format", format="n3")
201
+ url = url_for("api.site_rdf_catalog_format", _format="n3")
176
202
  response = client.get(url, headers={"Accept": "text/n3"})
177
203
  assert200(response)
178
204
  assert response.content_type == "text/n3"
179
205
 
180
206
  def test_catalog_rdf_turtle(self, client):
181
- url = url_for("api.site_rdf_catalog_format", format="ttl")
207
+ url = url_for("api.site_rdf_catalog_format", _format="ttl")
182
208
  response = client.get(url, headers={"Accept": "application/x-turtle"})
183
209
  assert200(response)
184
210
  assert response.content_type == "application/x-turtle"
185
211
 
186
212
  @pytest.mark.parametrize("fmt", ("xml", "rdf", "owl"))
187
213
  def test_catalog_rdf_rdfxml(self, fmt, client):
188
- url = url_for("api.site_rdf_catalog_format", format=fmt)
214
+ url = url_for("api.site_rdf_catalog_format", _format=fmt)
189
215
  response = client.get(url, headers={"Accept": "application/rdf+xml"})
190
216
  assert200(response)
191
217
  assert response.content_type == "application/rdf+xml"
192
218
 
193
219
  def test_catalog_rdf_n_triples(self, client):
194
- url = url_for("api.site_rdf_catalog_format", format="nt")
220
+ url = url_for("api.site_rdf_catalog_format", _format="nt")
195
221
  response = client.get(url, headers={"Accept": "application/n-triples"})
196
222
  assert200(response)
197
223
  assert response.content_type == "application/n-triples"
198
224
 
199
225
  def test_catalog_rdf_trig(self, client):
200
- url = url_for("api.site_rdf_catalog_format", format="trig")
226
+ url = url_for("api.site_rdf_catalog_format", _format="trig")
201
227
  response = client.get(url, headers={"Accept": "application/trig"})
202
228
  assert200(response)
203
229
  assert response.content_type == "application/trig"
204
230
 
205
231
  @pytest.mark.parametrize("fmt", ("json", "xml", "ttl"))
206
232
  def test_dataportal_compliance(self, fmt, client):
207
- url = url_for("api.site_dataportal", format=fmt)
233
+ url = url_for("api.site_dataportal", _format=fmt)
208
234
  assert url == "/api/1/site/data.{0}".format(fmt)
209
- expected_url = url_for("api.site_rdf_catalog_format", format=fmt)
235
+ expected_url = url_for("api.site_rdf_catalog_format", _format=fmt)
210
236
 
211
237
  response = client.get(url)
212
238
  assert_redirects(response, expected_url)
213
239
 
214
240
  def test_catalog_rdf_paginate(self, client):
215
- DatasetFactory.create_batch(4)
216
- url = url_for("api.site_rdf_catalog_format", format="n3", page_size=3)
241
+ DatasetFactory.create_batch(4, tags=["my-tag"])
242
+ DatasetFactory.create_batch(
243
+ 3, tags=["other-tag"]
244
+ ) # Shouldn't be returned because of the filter on tag="my-tag"
245
+ url = url_for("api.site_rdf_catalog_format", _format="n3", page_size=3, tag="my-tag")
217
246
  next_url = url_for(
218
- "api.site_rdf_catalog_format", format="n3", page=2, page_size=3, _external=True
247
+ "api.site_rdf_catalog_format",
248
+ _format="n3",
249
+ page=2,
250
+ page_size=3,
251
+ _external=True,
252
+ tag="my-tag",
219
253
  )
220
254
 
221
255
  response = client.get(url, headers={"Accept": "text/n3"})
@@ -227,16 +261,27 @@ class SiteRdfViewsTest:
227
261
  pagination = graph.resource(pagination)
228
262
  assert not pagination.value(HYDRA.previous)
229
263
  assert pagination.value(HYDRA.next).identifier == URIRef(next_url)
264
+ assert pagination.value(HYDRA.last).identifier == URIRef(next_url)
265
+ catalog = graph.value(predicate=RDF.type, object=HYDRA.Collection)
266
+ assert catalog is not None
267
+ catalog = graph.resource(catalog)
268
+ assert catalog.value(HYDRA.totalItems) == Literal(4)
230
269
 
231
270
  def test_catalog_format_unknown(self, client):
232
- url = url_for("api.site_rdf_catalog_format", format="unknown")
271
+ url = url_for("api.site_rdf_catalog_format", _format="unknown")
233
272
  response = client.get(url)
234
273
  assert404(response)
235
274
 
236
- def test_catalog_rdf_filter_tag(self, client):
275
+ def test_catalog_rdf_filter(self, client):
276
+ """
277
+ Test catalog RDF filter on tags and badges
278
+ """
237
279
  DatasetFactory.create_batch(4, tags=["my-tag"])
280
+ [dat.add_badge(HVD) for dat in DatasetFactory.create_batch(5)]
238
281
  DatasetFactory.create_batch(3)
239
- url = url_for("api.site_rdf_catalog_format", format="xml", tag="my-tag")
282
+
283
+ # Filter on tags
284
+ url = url_for("api.site_rdf_catalog_format", _format="xml", tag="my-tag")
240
285
 
241
286
  response = client.get(url, headers={"Accept": "application/xml"})
242
287
  assert200(response)
@@ -249,6 +294,17 @@ class SiteRdfViewsTest:
249
294
  for dat in datasets:
250
295
  assert graph.value(dat, DCAT.keyword) == Literal("my-tag")
251
296
 
297
+ # Filter on badge
298
+ url = url_for("api.site_rdf_catalog_format", _format="xml", badge=HVD)
299
+
300
+ response = client.get(url, headers={"Accept": "application/xml"})
301
+ assert200(response)
302
+
303
+ graph = Graph().parse(data=response.data, format="xml")
304
+
305
+ datasets = list(graph.subjects(RDF.type, DCAT.Dataset))
306
+ assert len(datasets) == 5
307
+
252
308
  def test_catalog_rdf_dataservices(self, client):
253
309
  dataset_a = DatasetFactory.create()
254
310
  dataset_b = DatasetFactory.create()
@@ -260,7 +316,7 @@ class SiteRdfViewsTest:
260
316
  dataservice_y = DataserviceFactory.create(datasets=[])
261
317
 
262
318
  response = client.get(
263
- url_for("api.site_rdf_catalog_format", format="xml"),
319
+ url_for("api.site_rdf_catalog_format", _format="xml"),
264
320
  headers={"Accept": "application/xml"},
265
321
  )
266
322
  assert200(response)
@@ -280,7 +336,7 @@ class SiteRdfViewsTest:
280
336
 
281
337
  # Test first page contains the dataservice without dataset
282
338
  response = client.get(
283
- url_for("api.site_rdf_catalog_format", format="xml", page_size=1),
339
+ url_for("api.site_rdf_catalog_format", _format="xml", page_size=1),
284
340
  headers={"Accept": "application/xml"},
285
341
  )
286
342
  assert200(response)
@@ -299,7 +355,7 @@ class SiteRdfViewsTest:
299
355
 
300
356
  # Test second page doesn't contains the dataservice without dataset
301
357
  response = client.get(
302
- url_for("api.site_rdf_catalog_format", format="xml", page_size=1, page=2),
358
+ url_for("api.site_rdf_catalog_format", _format="xml", page_size=1, page=2),
303
359
  headers={"Accept": "application/xml"},
304
360
  )
305
361
  assert200(response)
@@ -9,7 +9,7 @@ from udata.core.activity.models import Activity, Auditable
9
9
  from udata.core.organization.factories import OrganizationFactory
10
10
  from udata.core.user.factories import UserFactory
11
11
  from udata.models import db
12
- from udata.tests import DBTestMixin, TestCase, WebTestMixin
12
+ from udata.tests.api import APITestCase
13
13
  from udata.tests.helpers import assert_emit, assert_not_emit
14
14
 
15
15
 
@@ -45,7 +45,7 @@ class FakeActivity(Activity):
45
45
  related_to = db.ReferenceField(FakeSubject)
46
46
 
47
47
 
48
- class ActivityTest(WebTestMixin, DBTestMixin, TestCase):
48
+ class ActivityTest(APITestCase):
49
49
  def setUp(self):
50
50
  self.fake = FakeSubject.objects.create(name="fake")
51
51
  self.login()
@@ -120,7 +120,7 @@ class ActivityTest(WebTestMixin, DBTestMixin, TestCase):
120
120
  self.assertEqual(Activity.objects(actor=self.user).count(), 1)
121
121
 
122
122
 
123
- class AuditableTest(WebTestMixin, DBTestMixin, TestCase):
123
+ class AuditableTest(APITestCase):
124
124
  def test_auditable_signals_emission(self):
125
125
  """It should emit appropriate signals on subject fields creation, update and deletion"""
126
126
  with assert_emit(post_save, FakeAuditableSubject.on_create):
@@ -13,12 +13,9 @@ from udata.core.storages import default_image_basename, images
13
13
  from udata.factories import ModelFactory
14
14
  from udata.models import Badge, BadgeMixin, BadgesList, WithMetrics, db
15
15
  from udata.mongo.queryset import DBPaginator, UDataQuerySet
16
+ from udata.tests.api import PytestOnlyDBTestCase
16
17
  from udata.utils import faker
17
18
 
18
- pytestmark = [
19
- pytest.mark.usefixtures("clean_db"),
20
- ]
21
-
22
19
  BIGGEST_IMAGE_SIZE: int = 500
23
20
 
24
21
  BADGES: dict[str, str] = {
@@ -166,7 +163,7 @@ class FakeFactory(ModelFactory):
166
163
  archived = None
167
164
 
168
165
 
169
- class IndexParserTest:
166
+ class IndexParserTest(PytestOnlyDBTestCase):
170
167
  index_parser: RequestParser = Fake.__index_parser__
171
168
  index_parser_args: list[Argument] = Fake.__index_parser__.args
172
169
  index_parser_args_names: set[str] = set([field.name for field in Fake.__index_parser__.args])
@@ -233,7 +230,7 @@ class IndexParserTest:
233
230
  assert set(additional_sorts).issubset(set(choices))
234
231
 
235
232
 
236
- class PatchTest:
233
+ class PatchTest(PytestOnlyDBTestCase):
237
234
  fake_json = {"url": URL_RAISE_ERROR, "description": None}
238
235
 
239
236
  def test_patch_check(self) -> None:
@@ -249,7 +246,7 @@ class PatchTest:
249
246
  patch_and_save(fake, fake_request)
250
247
 
251
248
 
252
- class PatchEmbeddedTest:
249
+ class PatchEmbeddedTest(PytestOnlyDBTestCase):
253
250
  fake_json = {
254
251
  "url": URL_RAISE_ERROR,
255
252
  "description": "desc",
@@ -268,7 +265,7 @@ class PatchEmbeddedTest:
268
265
  patch_and_save(fake, fake_request)
269
266
 
270
267
 
271
- class ApplySortAndFiltersTest:
268
+ class ApplySortAndFiltersTest(PytestOnlyDBTestCase):
272
269
  def test_filterable_field(self, app) -> None:
273
270
  """A filterable field filters the results."""
274
271
  fake1: Fake = FakeFactory(filter_field="test filter")
@@ -334,7 +331,7 @@ class ApplySortAndFiltersTest:
334
331
  assert fake2 not in results
335
332
 
336
333
 
337
- class ApplyPaginationTest:
334
+ class ApplyPaginationTest(PytestOnlyDBTestCase):
338
335
  def test_default_pagination(self, app) -> None:
339
336
  """Results should be returned with default pagination."""
340
337
  [FakeFactory() for _ in range(100)]
udata/tests/test_cors.py CHANGED
@@ -8,8 +8,6 @@ from udata.tests.helpers import assert_status
8
8
 
9
9
 
10
10
  class CorsTest(APITestCase):
11
- modules = []
12
-
13
11
  def test_cors_on_allowed_routes(self):
14
12
  cors_headers = {
15
13
  "Origin": "http://localhost",
@@ -1,8 +1,7 @@
1
- import pytest
1
+ from udata.tests.api import PytestOnlyDBTestCase
2
2
 
3
3
 
4
- @pytest.mark.usefixtures("clean_db")
5
- class ParseUrlCommandTest:
4
+ class ParseUrlCommandTest(PytestOnlyDBTestCase):
6
5
  def test_parse_url(self, cli, requests_mock, caplog) -> None:
7
6
  logs = []
8
7
 
@@ -31,14 +31,11 @@ from udata.models import Dataset, Member
31
31
  from udata.tests.helpers import capture_mails
32
32
  from udata.utils import faker
33
33
 
34
- from . import DBTestMixin, TestCase
35
- from .api import APITestCase
34
+ from .api import APITestCase, DBTestCase
36
35
  from .helpers import assert_emit, assert_not_emit
37
36
 
38
37
 
39
38
  class DiscussionsTest(APITestCase):
40
- modules = []
41
-
42
39
  @pytest.mark.options(SPAM_WORDS=["spam"])
43
40
  def test_new_discussion(self):
44
41
  user = self.login()
@@ -1018,7 +1015,7 @@ class DiscussionsTest(APITestCase):
1018
1015
  self.assert403(response)
1019
1016
 
1020
1017
 
1021
- class DiscussionsNotificationsTest(TestCase, DBTestMixin):
1018
+ class DiscussionsNotificationsTest(DBTestCase):
1022
1019
  def test_notify_user_discussions(self):
1023
1020
  owner = UserFactory()
1024
1021
  dataset = DatasetFactory(owner=owner)
@@ -1091,8 +1088,6 @@ class DiscussionsNotificationsTest(TestCase, DBTestMixin):
1091
1088
 
1092
1089
 
1093
1090
  class DiscussionsMailsTest(APITestCase):
1094
- modules = []
1095
-
1096
1091
  def test_new_discussion_mail(self):
1097
1092
  user = UserFactory()
1098
1093
  owner = UserFactory()