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
@@ -15,6 +15,12 @@ from udata import uris
15
15
  from udata.api import fields
16
16
  from udata.app import cache
17
17
  from udata.core import storages
18
+ from udata.core.access_type.constants import (
19
+ AccessAudienceCondition,
20
+ AccessAudienceType,
21
+ AccessType,
22
+ InspireLimitationCategory,
23
+ )
18
24
  from udata.core.badges.factories import badge_factory
19
25
  from udata.core.dataset.constants import (
20
26
  DEFAULT_LICENSE,
@@ -36,17 +42,18 @@ from udata.core.dataset.models import (
36
42
  ResourceMixin,
37
43
  )
38
44
  from udata.core.organization.factories import OrganizationFactory
45
+ from udata.core.organization.models import OrganizationBadge
39
46
  from udata.core.spatial.factories import GeoLevelFactory, SpatialCoverageFactory
40
47
  from udata.core.topic.factories import TopicElementDatasetFactory, TopicFactory
41
48
  from udata.core.user.factories import AdminFactory, UserFactory
42
49
  from udata.i18n import gettext as _
43
50
  from udata.models import CommunityResource, Dataset, Follow, Member, db
44
- from udata.tags import MAX_TAG_LENGTH, MIN_TAG_LENGTH
51
+ from udata.tags import TAG_MAX_LENGTH, TAG_MIN_LENGTH
45
52
  from udata.tests.features.territories import create_geozones_fixtures
46
53
  from udata.tests.helpers import assert200, assert404
47
54
  from udata.utils import faker, unique_string
48
55
 
49
- from . import APITestCase
56
+ from . import APITestCase, PytestOnlyAPITestCase
50
57
 
51
58
  SAMPLE_GEOM = {
52
59
  "type": "MultiPolygon",
@@ -66,8 +73,6 @@ def dataset_in_response(response: TestResponse, dataset: Dataset) -> bool:
66
73
 
67
74
 
68
75
  class DatasetAPITest(APITestCase):
69
- modules = []
70
-
71
76
  def test_dataset_api_list(self):
72
77
  """It should fetch a dataset list from the API"""
73
78
  datasets = [DatasetFactory() for i in range(2)]
@@ -631,19 +636,21 @@ class DatasetAPITest(APITestCase):
631
636
  dataset = Dataset.objects.first()
632
637
  self.assertEqual(dataset.tags, sorted(data["tags"]))
633
638
 
639
+ @pytest.mark.options(TAG_MIN_LENGTH=3, TAG_MAX_LENGTH=10)
634
640
  def test_dataset_api_fail_to_create_too_short_tags(self):
635
641
  """It should fail to create a dataset from the API because
636
642
  the tag is too short"""
637
643
  data = DatasetFactory.as_dict()
638
- data["tags"] = [unique_string(MIN_TAG_LENGTH - 1)]
644
+ data["tags"] = [unique_string(TAG_MIN_LENGTH - 1)]
639
645
  with self.api_user():
640
646
  response = self.post(url_for("api.datasets"), data)
641
647
  self.assertStatus(response, 400)
642
648
 
649
+ @pytest.mark.options(TAG_MIN_LENGTH=3, TAG_MAX_LENGTH=10)
643
650
  def test_dataset_api_fail_to_create_too_long_tags(self):
644
651
  """Should fail creating a dataset with a tag long"""
645
652
  data = DatasetFactory.as_dict()
646
- data["tags"] = [unique_string(MAX_TAG_LENGTH + 1)]
653
+ data["tags"] = [unique_string(TAG_MAX_LENGTH + 1)]
647
654
  with self.api_user():
648
655
  response = self.post(url_for("api.datasets"), data)
649
656
  self.assertStatus(response, 400)
@@ -740,6 +747,18 @@ class DatasetAPITest(APITestCase):
740
747
  self.assertEqual(Dataset.objects.count(), 1)
741
748
  self.assertEqual(Dataset.objects.first().description, "new description")
742
749
 
750
+ def test_dataset_api_update_with_null_frequency(self):
751
+ """It should update the item even though internal frequency is null"""
752
+ user = self.login()
753
+ dataset = DatasetFactory(owner=user, frequency=None)
754
+ data = dataset.to_dict()
755
+ # Update doesn't matter as long as we don't touch `frequency`
756
+ data["tags"] = ["test"]
757
+ response = self.put(url_for("api.dataset", dataset=dataset), data)
758
+ self.assert200(response)
759
+ self.assertEqual(Dataset.objects.count(), 1)
760
+ self.assertEqual(Dataset.objects.first().frequency, None)
761
+
743
762
  def test_dataset_api_update_valid_frequency(self):
744
763
  """It should update a dataset from the API"""
745
764
  user = self.login()
@@ -1320,33 +1339,150 @@ class DatasetAPITest(APITestCase):
1320
1339
  assert dataset.resources[0].title == "updated 2"
1321
1340
  assert dataset.resources[0].schema is None
1322
1341
 
1342
+ def test_add_access_type(self):
1343
+ self.login(AdminFactory())
1344
+ dataset = DatasetFactory()
1345
+ assert dataset.access_type == AccessType.OPEN
1346
+
1347
+ response = self.get(url_for("api.dataset", dataset=dataset))
1348
+
1349
+ self.assert200(response)
1350
+ assert response.json["access_type"] == AccessType.OPEN
1351
+
1352
+ response = self.put(
1353
+ url_for("api.dataset", dataset=dataset),
1354
+ {
1355
+ "access_type": AccessType.RESTRICTED,
1356
+ "access_audiences": [
1357
+ {
1358
+ "role": AccessAudienceType.ADMINISTRATION,
1359
+ "condition": AccessAudienceCondition.YES,
1360
+ },
1361
+ {"role": AccessAudienceType.COMPANY, "condition": AccessAudienceCondition.NO},
1362
+ {
1363
+ "role": AccessAudienceType.PRIVATE,
1364
+ "condition": AccessAudienceCondition.UNDER_CONDITIONS,
1365
+ },
1366
+ ],
1367
+ "authorization_request_url": "https://example.org",
1368
+ "access_type_reason_category": InspireLimitationCategory.INTERNATIONAL_RELATIONS,
1369
+ "access_type_reason": "Les données contiennent des information sensibles ou liées au secret défense",
1370
+ },
1371
+ )
1372
+
1373
+ self.assert200(response)
1374
+ assert response.json["access_type"] == AccessType.RESTRICTED
1375
+ assert (
1376
+ response.json["access_type_reason_category"]
1377
+ == InspireLimitationCategory.INTERNATIONAL_RELATIONS
1378
+ )
1379
+ assert (
1380
+ response.json["access_type_reason"]
1381
+ == "Les données contiennent des information sensibles ou liées au secret défense"
1382
+ )
1383
+ assert response.json["access_audiences"][0]["role"] == AccessAudienceType.ADMINISTRATION
1384
+ assert response.json["access_audiences"][0]["condition"] == AccessAudienceCondition.YES
1385
+ assert "id" not in response.json["access_audiences"][0]
1386
+
1387
+ dataset.reload()
1388
+ assert dataset.access_type == AccessType.RESTRICTED
1389
+ assert dataset.access_audiences[0].role == AccessAudienceType.ADMINISTRATION
1390
+ assert dataset.access_audiences[0].condition == AccessAudienceCondition.YES
1391
+ assert dataset.access_audiences[1].role == AccessAudienceType.COMPANY
1392
+ assert dataset.access_audiences[1].condition == AccessAudienceCondition.NO
1393
+ assert dataset.access_audiences[2].role == AccessAudienceType.PRIVATE
1394
+ assert dataset.access_audiences[2].condition == AccessAudienceCondition.UNDER_CONDITIONS
1395
+ assert dataset.authorization_request_url == "https://example.org"
1396
+ assert (
1397
+ dataset.access_type_reason_category == InspireLimitationCategory.INTERNATIONAL_RELATIONS
1398
+ )
1399
+ assert (
1400
+ dataset.access_type_reason
1401
+ == "Les données contiennent des information sensibles ou liées au secret défense"
1402
+ )
1403
+
1404
+ def test_cannot_duplicate_access_audiences(self):
1405
+ self.login(AdminFactory())
1406
+ dataset = DatasetFactory()
1407
+
1408
+ response = self.put(
1409
+ url_for("api.dataset", dataset=dataset),
1410
+ {
1411
+ "access_type": AccessType.RESTRICTED,
1412
+ "access_audiences": [
1413
+ {
1414
+ "role": AccessAudienceType.ADMINISTRATION,
1415
+ "condition": AccessAudienceCondition.YES,
1416
+ },
1417
+ {
1418
+ "role": AccessAudienceType.ADMINISTRATION,
1419
+ "condition": AccessAudienceCondition.YES,
1420
+ },
1421
+ ],
1422
+ },
1423
+ )
1424
+
1425
+ self.assert400(response)
1426
+
1427
+ def test_reset_license_on_restricted(self):
1428
+ self.login(AdminFactory())
1429
+ dataset = DatasetFactory(license=LicenseFactory(id="cc-by"))
1430
+
1431
+ response = self.put(
1432
+ url_for("api.dataset", dataset=dataset),
1433
+ {
1434
+ "access_type": AccessType.RESTRICTED,
1435
+ },
1436
+ )
1437
+
1438
+ self.assert200(response)
1439
+
1440
+ dataset.reload()
1441
+ assert dataset.license is None
1442
+
1323
1443
 
1324
1444
  class DatasetsFeedAPItest(APITestCase):
1445
+ @pytest.mark.options(DELAY_BEFORE_APPEARING_IN_RSS_FEED=10)
1325
1446
  def test_recent_feed(self):
1447
+ certified_org = OrganizationFactory(badges=[OrganizationBadge(kind="certified")])
1448
+ # We have a 10 hours delay for a new object to appear in feed. A newly created one shouldn't appear.
1326
1449
  DatasetFactory(
1327
1450
  title="A", resources=[ResourceFactory()], created_at_internal=datetime.utcnow()
1328
1451
  )
1452
+ # Except in the case of a new dataset published by a certified organization
1329
1453
  DatasetFactory(
1330
1454
  title="B",
1331
- resources=[ResourceFactory()],
1332
- created_at_internal=datetime.utcnow() - timedelta(days=2),
1455
+ created_at_internal=datetime.utcnow(),
1456
+ organization=certified_org,
1333
1457
  )
1334
1458
  DatasetFactory(
1335
1459
  title="C",
1336
- resources=[ResourceFactory()],
1460
+ created_at_internal=datetime.utcnow() - timedelta(days=2),
1461
+ )
1462
+ DatasetFactory(
1463
+ title="D",
1337
1464
  created_at_internal=datetime.utcnow() - timedelta(days=1),
1338
1465
  )
1466
+ # Even if dataset E is created more recently than D, it should appear after in the feed, since it doesn't have a delay
1467
+ # before appearing in the field because it is published by a certified organization
1468
+ DatasetFactory(
1469
+ title="E",
1470
+ created_at_internal=datetime.utcnow() - timedelta(hours=23),
1471
+ organization=certified_org,
1472
+ )
1339
1473
 
1340
1474
  response = self.get(url_for("api.recent_datasets_atom_feed"))
1341
1475
  self.assert200(response)
1342
1476
 
1343
1477
  feed = feedparser.parse(response.data)
1344
1478
 
1345
- self.assertEqual(len(feed.entries), 3)
1346
- self.assertEqual(feed.entries[0].title, "A")
1347
- self.assertEqual(feed.entries[1].title, "C")
1348
- self.assertEqual(feed.entries[2].title, "B")
1479
+ self.assertEqual(len(feed.entries), 4)
1480
+ self.assertEqual(feed.entries[0].title, "B")
1481
+ self.assertEqual(feed.entries[1].title, "D")
1482
+ self.assertEqual(feed.entries[2].title, "E")
1483
+ self.assertEqual(feed.entries[3].title, "C")
1349
1484
 
1485
+ @pytest.mark.options(DELAY_BEFORE_APPEARING_IN_RSS_FEED=0)
1350
1486
  def test_recent_feed_owner(self):
1351
1487
  owner = UserFactory()
1352
1488
  DatasetFactory(owner=owner, resources=[ResourceFactory()])
@@ -1364,6 +1500,7 @@ class DatasetsFeedAPItest(APITestCase):
1364
1500
  self.assertEqual(author.name, owner.fullname)
1365
1501
  self.assertEqual(author.href, owner.url_for())
1366
1502
 
1503
+ @pytest.mark.options(DELAY_BEFORE_APPEARING_IN_RSS_FEED=0)
1367
1504
  def test_recent_feed_org(self):
1368
1505
  owner = UserFactory()
1369
1506
  org = OrganizationFactory()
@@ -1393,7 +1530,7 @@ class DatasetsFeedAPItest(APITestCase):
1393
1530
  assert "<h1>" in response.text
1394
1531
  assert "<ul>" in response.text
1395
1532
 
1396
- @pytest.mark.options(DELAY_BEFORE_APPEARING_IN_RSS_FEED=0)
1533
+ @pytest.mark.options(DELAY_BEFORE_APPEARING_IN_RSS_FEED=0, CDATA_BASE_URL="http://example.org")
1397
1534
  def test_feed_id_uri_is_valid(self):
1398
1535
  DatasetFactory()
1399
1536
 
@@ -1473,8 +1610,6 @@ class DatasetBadgeAPITest(APITestCase):
1473
1610
 
1474
1611
 
1475
1612
  class DatasetResourceAPITest(APITestCase):
1476
- modules = None
1477
-
1478
1613
  def setUp(self):
1479
1614
  self.login()
1480
1615
  self.dataset = DatasetFactory(owner=self.user)
@@ -1923,35 +2058,25 @@ class DatasetResourceAPITest(APITestCase):
1923
2058
  self.assertEqual(Follow.objects.following(user).count(), 0)
1924
2059
  self.assertEqual(Follow.objects.followers(user).count(), 0)
1925
2060
 
2061
+ @pytest.mark.options(ALLOWED_RESOURCES_EXTENSIONS=["txt", "html", "kml", "kml-1", "qml", "xml"])
1926
2062
  def test_suggest_formats_api(self):
1927
- """It should suggest formats"""
1928
- DatasetFactory(
1929
- resources=[
1930
- ResourceFactory(format=f) for f in (faker.word(), faker.word(), "kml", "kml-1")
1931
- ]
1932
- )
1933
-
1934
- response = self.get(url_for("api.suggest_formats"), qs={"q": "km", "size": "5"})
2063
+ response = self.get(url_for("api.suggest_formats", q="km", size=5))
1935
2064
  self.assert200(response)
1936
2065
 
1937
- self.assertLessEqual(len(response.json), 5)
1938
- self.assertGreater(len(response.json), 1)
1939
-
1940
- for suggestion in response.json:
1941
- self.assertIn("text", suggestion)
1942
- self.assertIn("km", suggestion["text"])
2066
+ self.assertEqual(len(response.json), 2)
2067
+ self.assertEqual(response.json[0]["text"], "kml")
2068
+ self.assertEqual(response.json[1]["text"], "kml-1")
1943
2069
 
2070
+ @pytest.mark.options(ALLOWED_RESOURCES_EXTENSIONS=["txt", "html", "kml", "kml-1", "qml", "xml"])
1944
2071
  def test_suggest_format_api_no_match(self):
1945
- """It should not provide format suggestion if no match"""
1946
- DatasetFactory(resources=[ResourceFactory(format=faker.word()) for _ in range(3)])
1947
-
1948
- response = self.get(url_for("api.suggest_formats"), qs={"q": "test", "size": "5"})
2072
+ response = self.get(url_for("api.suggest_formats", q="test", size=5))
1949
2073
  self.assert200(response)
1950
2074
  self.assertEqual(len(response.json), 0)
1951
2075
 
2076
+ @pytest.mark.options(ALLOWED_RESOURCES_EXTENSIONS=[])
1952
2077
  def test_suggest_format_api_empty(self):
1953
2078
  """It should not provide format suggestion if no data"""
1954
- response = self.get(url_for("api.suggest_formats"), qs={"q": "test", "size": "5"})
2079
+ response = self.get(url_for("api.suggest_formats", q="txt", size=5))
1955
2080
  self.assert200(response)
1956
2081
  self.assertEqual(len(response.json), 0)
1957
2082
 
@@ -1969,7 +2094,7 @@ class DatasetResourceAPITest(APITestCase):
1969
2094
  ]
1970
2095
  )
1971
2096
 
1972
- response = self.get(url_for("api.suggest_mime"), qs={"q": "js", "size": "5"})
2097
+ response = self.get(url_for("api.suggest_mime", q="js", size=5))
1973
2098
  self.assert200(response)
1974
2099
  self.assertLessEqual(len(response.json), 5)
1975
2100
 
@@ -1980,7 +2105,7 @@ class DatasetResourceAPITest(APITestCase):
1980
2105
  """It should suggest mime types"""
1981
2106
  DatasetFactory(resources=[ResourceFactory(mime="application/xhtml+xml")])
1982
2107
 
1983
- response = self.get(url_for("api.suggest_mime"), qs={"q": "xml", "size": "5"})
2108
+ response = self.get(url_for("api.suggest_mime", q="xml", size=5))
1984
2109
  self.assert200(response)
1985
2110
 
1986
2111
  self.assertEqual(len(response.json), 5)
@@ -1989,13 +2114,13 @@ class DatasetResourceAPITest(APITestCase):
1989
2114
  """It should not provide format suggestion if no match"""
1990
2115
  DatasetFactory(resources=[ResourceFactory(mime=faker.word()) for _ in range(3)])
1991
2116
 
1992
- response = self.get(url_for("api.suggest_mime"), qs={"q": "test", "size": "5"})
2117
+ response = self.get(url_for("api.suggest_mime", q="test", size=5))
1993
2118
  self.assert200(response)
1994
2119
  self.assertEqual(len(response.json), 0)
1995
2120
 
1996
2121
  def test_suggest_mime_api_empty(self):
1997
2122
  """It should not provide mime suggestion if no data"""
1998
- response = self.get(url_for("api.suggest_mime"), qs={"q": "test", "size": "5"})
2123
+ response = self.get(url_for("api.suggest_mime", q="test", size=5))
1999
2124
  self.assert200(response)
2000
2125
  self.assertEqual(len(response.json), 0)
2001
2126
 
@@ -2011,7 +2136,7 @@ class DatasetResourceAPITest(APITestCase):
2011
2136
  title="title-test-4", visible=True, metrics={"followers": 10}
2012
2137
  )
2013
2138
 
2014
- response = self.get(url_for("api.suggest_datasets"), qs={"q": "title-test", "size": "5"})
2139
+ response = self.get(url_for("api.suggest_datasets", q="title-test", size=5))
2015
2140
  self.assert200(response)
2016
2141
 
2017
2142
  self.assertLessEqual(len(response.json), 5)
@@ -2034,7 +2159,7 @@ class DatasetResourceAPITest(APITestCase):
2034
2159
  visible=True,
2035
2160
  )
2036
2161
 
2037
- response = self.get(url_for("api.suggest_datasets"), qs={"q": "acronym-test", "size": "5"})
2162
+ response = self.get(url_for("api.suggest_datasets", q="acronym-test", size=5))
2038
2163
  self.assert200(response)
2039
2164
 
2040
2165
  self.assertLessEqual(len(response.json), 5)
@@ -2056,7 +2181,7 @@ class DatasetResourceAPITest(APITestCase):
2056
2181
  resources=[ResourceFactory()],
2057
2182
  )
2058
2183
 
2059
- response = self.get(url_for("api.suggest_datasets"), qs={"q": "title-testé", "size": "5"})
2184
+ response = self.get(url_for("api.suggest_datasets", q="title-testé", size=5))
2060
2185
  self.assert200(response)
2061
2186
 
2062
2187
  self.assertLessEqual(len(response.json), 5)
@@ -2074,13 +2199,13 @@ class DatasetResourceAPITest(APITestCase):
2074
2199
  for i in range(3):
2075
2200
  DatasetFactory(resources=[ResourceFactory()])
2076
2201
 
2077
- response = self.get(url_for("api.suggest_datasets"), qs={"q": "xxxxxx", "size": "5"})
2202
+ response = self.get(url_for("api.suggest_datasets", q="xxxxxx", size=5))
2078
2203
  self.assert200(response)
2079
2204
  self.assertEqual(len(response.json), 0)
2080
2205
 
2081
2206
  def test_suggest_datasets_api_empty(self):
2082
2207
  """It should not provide dataset suggestion if no data"""
2083
- response = self.get(url_for("api.suggest_datasets"), qs={"q": "xxxxxx", "size": "5"})
2208
+ response = self.get(url_for("api.suggest_datasets", q="xxxxxx", size=5))
2084
2209
  self.assert200(response)
2085
2210
  self.assertEqual(len(response.json), 0)
2086
2211
 
@@ -2110,8 +2235,6 @@ class DatasetReferencesAPITest(APITestCase):
2110
2235
 
2111
2236
 
2112
2237
  class DatasetArchivedAPITest(APITestCase):
2113
- modules = []
2114
-
2115
2238
  def test_dataset_api_search_archived(self):
2116
2239
  """It should search datasets from the API, excluding archived ones"""
2117
2240
  DatasetFactory(archived=None)
@@ -2130,8 +2253,6 @@ class DatasetArchivedAPITest(APITestCase):
2130
2253
 
2131
2254
 
2132
2255
  class CommunityResourceAPITest(APITestCase):
2133
- modules = []
2134
-
2135
2256
  def test_community_resource_api_get(self):
2136
2257
  """It should fetch a community resource from the API"""
2137
2258
  community_resource = CommunityResourceFactory()
@@ -2385,10 +2506,7 @@ class ResourcesTypesAPITest(APITestCase):
2385
2506
  self.assertEqual(len(response.json), len(RESOURCE_TYPES))
2386
2507
 
2387
2508
 
2388
- @pytest.mark.usefixtures("clean_db")
2389
- class DatasetSchemasAPITest:
2390
- modules = []
2391
-
2509
+ class DatasetSchemasAPITest(PytestOnlyAPITestCase):
2392
2510
  def test_dataset_schemas_api_list(self, api, rmock, app):
2393
2511
  # Can't use @pytest.mark.options otherwise a request will be
2394
2512
  # made before setting up rmock at module load, resulting in a 404
@@ -2449,10 +2567,7 @@ class DatasetSchemasAPITest:
2449
2567
  )
2450
2568
 
2451
2569
 
2452
- @pytest.mark.usefixtures("clean_db")
2453
- class HarvestMetadataAPITest:
2454
- modules = []
2455
-
2570
+ class HarvestMetadataAPITest(PytestOnlyAPITestCase):
2456
2571
  def test_dataset_with_harvest_metadata(self, api):
2457
2572
  date = datetime(2022, 2, 22, tzinfo=pytz.UTC)
2458
2573
  harvest_metadata = HarvestDatasetMetadata(
@@ -18,8 +18,6 @@ from . import APITestCase
18
18
 
19
19
 
20
20
  class MeAPITest(APITestCase):
21
- modules = []
22
-
23
21
  def test_get_profile(self):
24
22
  """It should fetch my user data on GET"""
25
23
  self.login()
@@ -105,7 +103,7 @@ class MeAPITest(APITestCase):
105
103
  DatasetFactory(owner=user)
106
104
  DatasetFactory(organization=organization)
107
105
 
108
- response = self.get(url_for("api.my_org_datasets"), qs={"q": "foô"})
106
+ response = self.get(url_for("api.my_org_datasets", q="foô"))
109
107
  self.assert200(response)
110
108
  self.assertEqual(len(response.json), len(datasets) + len(org_datasets))
111
109
 
@@ -139,7 +137,7 @@ class MeAPITest(APITestCase):
139
137
  CommunityResourceFactory(owner=user)
140
138
  CommunityResourceFactory(organization=organization)
141
139
 
142
- response = self.get(url_for("api.my_org_community_resources"), qs={"q": "foô"})
140
+ response = self.get(url_for("api.my_org_community_resources", q="foô"))
143
141
  self.assert200(response)
144
142
  self.assertEqual(
145
143
  len(response.json), len(community_resources) + len(org_community_resources)
@@ -171,7 +169,7 @@ class MeAPITest(APITestCase):
171
169
  ReuseFactory(owner=user)
172
170
  ReuseFactory(organization=organization)
173
171
 
174
- response = self.get(url_for("api.my_org_reuses"), qs={"q": "foô"})
172
+ response = self.get(url_for("api.my_org_reuses", q="foô"))
175
173
  self.assert200(response)
176
174
  self.assertEqual(len(response.json), len(reuses) + len(org_reuses))
177
175
 
@@ -221,7 +219,7 @@ class MeAPITest(APITestCase):
221
219
  Discussion.objects.create(subject=DatasetFactory(), title="foô", user=user)
222
220
  Discussion.objects.create(subject=ReuseFactory(), title="foô", user=user)
223
221
 
224
- response = self.get(url_for("api.my_org_discussions"), qs={"q": "foô"})
222
+ response = self.get(url_for("api.my_org_discussions", q="foô"))
225
223
  self.assert200(response)
226
224
  self.assertEqual(len(response.json), len(discussions))
227
225
 
@@ -16,6 +16,7 @@ from udata.core.reuse.factories import ReuseFactory
16
16
  from udata.core.user.factories import AdminFactory, UserFactory
17
17
  from udata.i18n import _
18
18
  from udata.models import Discussion, Follow, Member, MembershipRequest, Organization
19
+ from udata.tests.api import PytestOnlyAPITestCase
19
20
  from udata.tests.helpers import (
20
21
  assert200,
21
22
  assert201,
@@ -31,14 +32,8 @@ from udata.tests.helpers import (
31
32
  )
32
33
  from udata.utils import faker
33
34
 
34
- pytestmark = [
35
- pytest.mark.usefixtures("clean_db"),
36
- ]
37
-
38
-
39
- class OrganizationAPITest:
40
- modules = []
41
35
 
36
+ class OrganizationAPITest(PytestOnlyAPITestCase):
42
37
  def test_organization_api_list(self, api):
43
38
  """It should fetch an organization list from the API"""
44
39
  organizations = OrganizationFactory.create_batch(3)
@@ -235,9 +230,7 @@ class OrganizationAPITest:
235
230
  assert Organization.objects[0].deleted is None
236
231
 
237
232
 
238
- class MembershipAPITest:
239
- modules = []
240
-
233
+ class MembershipAPITest(PytestOnlyAPITestCase):
241
234
  def test_request_membership(self, api):
242
235
  organization = OrganizationFactory()
243
236
  user = api.login()
@@ -678,7 +671,7 @@ class MembershipAPITest:
678
671
  name="test-{0}".format(i) if i % 2 else faker.word(), metrics={"followers": i}
679
672
  )
680
673
  max_follower_organization = OrganizationFactory(name="test-4", metrics={"followers": 10})
681
- response = api.get(url_for("api.suggest_organizations"), qs={"q": "tes", "size": "5"})
674
+ response = api.get(url_for("api.suggest_organizations", q="tes", size=5))
682
675
  assert200(response)
683
676
 
684
677
  assert len(response.json) <= 5
@@ -698,7 +691,7 @@ class MembershipAPITest:
698
691
  for i in range(4):
699
692
  OrganizationFactory(name="testé-{0}".format(i) if i % 2 else faker.word())
700
693
 
701
- response = api.get(url_for("api.suggest_organizations"), qs={"q": "testé", "size": "5"})
694
+ response = api.get(url_for("api.suggest_organizations", q="testé", size=5))
702
695
  assert200(response)
703
696
 
704
697
  assert len(response.json) <= 5
@@ -716,7 +709,7 @@ class MembershipAPITest:
716
709
  for i in range(4):
717
710
  OrganizationFactory(name="mon testé-{0}".format(i) if i % 2 else faker.word())
718
711
 
719
- response = api.get(url_for("api.suggest_organizations"), qs={"q": "mon testé", "size": "5"})
712
+ response = api.get(url_for("api.suggest_organizations", q="mon testé", size=5))
720
713
  assert200(response)
721
714
 
722
715
  assert len(response.json) <= 5
@@ -736,7 +729,7 @@ class MembershipAPITest:
736
729
  name="Ministère de l'intérieur {0}".format(i) if i % 2 else faker.word()
737
730
  )
738
731
 
739
- response = api.get(url_for("api.suggest_organizations"), qs={"q": "Ministère", "size": "5"})
732
+ response = api.get(url_for("api.suggest_organizations", q="Ministère", size=5))
740
733
  assert200(response)
741
734
 
742
735
  assert len(response.json) <= 5
@@ -753,13 +746,13 @@ class MembershipAPITest:
753
746
  """It should not provide organization suggestion if no match"""
754
747
  OrganizationFactory.create_batch(3)
755
748
 
756
- response = api.get(url_for("api.suggest_organizations"), qs={"q": "xxxxxx", "size": "5"})
749
+ response = api.get(url_for("api.suggest_organizations", q="xxxxxx", size=5))
757
750
  assert200(response)
758
751
  assert len(response.json) == 0
759
752
 
760
753
  def test_suggest_organizations_api_empty(self, api):
761
754
  """It should not provide organization suggestion if no data"""
762
- response = api.get(url_for("api.suggest_organizations"), qs={"q": "xxxxxx", "size": "5"})
755
+ response = api.get(url_for("api.suggest_organizations", q="xxxxxx", size=5))
763
756
  assert200(response)
764
757
  assert len(response.json) == 0
765
758
 
@@ -767,7 +760,7 @@ class MembershipAPITest:
767
760
  """It should suggest organizations and not deduplicate homonyms"""
768
761
  OrganizationFactory.create_batch(2, name="homonym")
769
762
 
770
- response = api.get(url_for("api.suggest_organizations"), qs={"q": "homonym", "size": "5"})
763
+ response = api.get(url_for("api.suggest_organizations", q="homonym", size=5))
771
764
  assert200(response)
772
765
 
773
766
  assert len(response.json) == 2
@@ -787,7 +780,7 @@ class MembershipAPITest:
787
780
  max_follower_organization = OrganizationFactory(
788
781
  name=faker.word(), acronym="UDATA4", metrics={"followers": 10}
789
782
  )
790
- response = api.get(url_for("api.suggest_organizations"), qs={"q": "uDaTa", "size": "5"})
783
+ response = api.get(url_for("api.suggest_organizations", q="uDaTa", size=5))
791
784
  assert200(response)
792
785
 
793
786
  assert len(response.json) == 2
@@ -802,9 +795,7 @@ class MembershipAPITest:
802
795
  assert response.json[0]["id"] == str(max_follower_organization.id)
803
796
 
804
797
 
805
- class OrganizationDatasetsAPITest:
806
- modules = []
807
-
798
+ class OrganizationDatasetsAPITest(PytestOnlyAPITestCase):
808
799
  def test_list_org_datasets(self, api):
809
800
  """Should list organization datasets"""
810
801
  org = OrganizationFactory()
@@ -843,15 +834,13 @@ class OrganizationDatasetsAPITest:
843
834
  org = OrganizationFactory()
844
835
  DatasetFactory.create_batch(3, organization=org)
845
836
 
846
- response = api.get(url_for("api.org_datasets", org=org), qs={"page_size": 2})
837
+ response = api.get(url_for("api.org_datasets", org=org, page_size=2))
847
838
 
848
839
  assert200(response)
849
840
  assert len(response.json["data"]) == 2
850
841
 
851
842
 
852
- class OrganizationReusesAPITest:
853
- modules = []
854
-
843
+ class OrganizationReusesAPITest(PytestOnlyAPITestCase):
855
844
  def test_list_org_reuses(self, api):
856
845
  """Should list organization reuses"""
857
846
  org = OrganizationFactory()
@@ -886,9 +875,7 @@ class OrganizationReusesAPITest:
886
875
  assert len(response.json) == len(reuses)
887
876
 
888
877
 
889
- class OrganizationDiscussionsAPITest:
890
- modules = []
891
-
878
+ class OrganizationDiscussionsAPITest(PytestOnlyAPITestCase):
892
879
  def test_list_org_discussions(self, api):
893
880
  """Should list organization discussions"""
894
881
  user = UserFactory()
@@ -910,11 +897,9 @@ class OrganizationDiscussionsAPITest:
910
897
  assert discussion["id"] in discussions_ids
911
898
 
912
899
 
913
- class OrganizationBadgeAPITest:
914
- modules = []
915
-
900
+ class OrganizationBadgeAPITest(PytestOnlyAPITestCase):
916
901
  @pytest.fixture(autouse=True)
917
- def setUp(self, api, clean_db):
902
+ def setup_func(self, api):
918
903
  self.factory = badge_factory(Organization)
919
904
  self.user = api.login(AdminFactory())
920
905
  self.organization = OrganizationFactory()
@@ -978,9 +963,7 @@ class OrganizationBadgeAPITest:
978
963
  assert404(response)
979
964
 
980
965
 
981
- class OrganizationContactPointsAPITest:
982
- modules = []
983
-
966
+ class OrganizationContactPointsAPITest(PytestOnlyAPITestCase):
984
967
  def test_org_contact_points(self, api):
985
968
  user = api.login()
986
969
  member = Member(user=user, role="admin")
@@ -1027,9 +1010,7 @@ class OrganizationContactPointsAPITest:
1027
1010
  assert len(response.json) == 0
1028
1011
 
1029
1012
 
1030
- class OrganizationCsvExportsTest:
1031
- modules = []
1032
-
1013
+ class OrganizationCsvExportsTest(PytestOnlyAPITestCase):
1033
1014
  def test_datasets_csv(self, api):
1034
1015
  org = OrganizationFactory()
1035
1016
  [DatasetFactory(organization=org, resources=[ResourceFactory()]) for _ in range(3)]
@@ -15,8 +15,6 @@ from . import APITestCase
15
15
 
16
16
 
17
17
  class ReportsReasonsAPITest(APITestCase):
18
- modules = []
19
-
20
18
  def test_reports_reasons_api(self):
21
19
  response = self.get(url_for("api.reports_reasons"))
22
20
  self.assert200(response)
@@ -24,8 +22,6 @@ class ReportsReasonsAPITest(APITestCase):
24
22
 
25
23
 
26
24
  class ReportsAPITest(APITestCase):
27
- modules = []
28
-
29
25
  def test_reports_api_create(self):
30
26
  user = UserFactory()
31
27