udata 12.0.2.dev15__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 (258) 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 -3
  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 +3 -3
  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_fields.py +11 -0
  29. udata/core/dataset/apiv2.py +11 -0
  30. udata/core/dataset/constants.py +0 -1
  31. udata/core/dataset/forms.py +29 -0
  32. udata/core/dataset/models.py +16 -4
  33. udata/core/dataset/rdf.py +2 -1
  34. udata/core/dataset/search.py +2 -2
  35. udata/core/dataset/tasks.py +86 -8
  36. udata/core/discussions/mails.py +63 -0
  37. udata/core/discussions/tasks.py +4 -18
  38. udata/core/metrics/__init__.py +0 -6
  39. udata/core/organization/api.py +3 -1
  40. udata/core/organization/mails.py +144 -0
  41. udata/core/organization/models.py +2 -1
  42. udata/core/organization/search.py +1 -1
  43. udata/core/organization/tasks.py +21 -49
  44. udata/core/pages/tests/test_api.py +0 -2
  45. udata/core/reuse/api.py +27 -1
  46. udata/core/reuse/mails.py +21 -0
  47. udata/core/reuse/models.py +10 -1
  48. udata/core/reuse/search.py +1 -1
  49. udata/core/reuse/tasks.py +2 -3
  50. udata/core/site/models.py +2 -6
  51. udata/core/spatial/tests/test_api.py +17 -20
  52. udata/core/spatial/tests/test_models.py +3 -3
  53. udata/core/user/mails.py +54 -0
  54. udata/core/user/models.py +2 -3
  55. udata/core/user/tasks.py +8 -23
  56. udata/core/user/tests/test_user_model.py +2 -6
  57. udata/entrypoints.py +0 -5
  58. udata/features/identicon/tests/test_backends.py +3 -13
  59. udata/forms/fields.py +3 -3
  60. udata/forms/widgets.py +2 -2
  61. udata/frontend/__init__.py +3 -32
  62. udata/harvest/actions.py +4 -9
  63. udata/harvest/api.py +5 -14
  64. udata/harvest/backends/__init__.py +20 -11
  65. udata/harvest/backends/base.py +2 -2
  66. udata/harvest/backends/ckan/harvesters.py +2 -1
  67. udata/harvest/backends/dcat.py +3 -0
  68. udata/harvest/backends/maaf.py +1 -0
  69. udata/harvest/commands.py +6 -4
  70. udata/harvest/forms.py +9 -6
  71. udata/harvest/tasks.py +3 -5
  72. udata/harvest/tests/ckan/test_ckan_backend.py +300 -337
  73. udata/harvest/tests/ckan/test_ckan_backend_errors.py +94 -99
  74. udata/harvest/tests/ckan/test_ckan_backend_filters.py +128 -122
  75. udata/harvest/tests/ckan/test_dkan_backend.py +39 -51
  76. udata/harvest/tests/dcat/datara--5a26b0f6-0ccf-46ad-ac58-734054b91977.rdf.xml +255 -0
  77. udata/harvest/tests/dcat/datara--f40c3860-7236-4b30-a141-23b8ae33f7b2.rdf.xml +289 -0
  78. udata/harvest/tests/factories.py +1 -1
  79. udata/harvest/tests/test_actions.py +11 -9
  80. udata/harvest/tests/test_api.py +4 -5
  81. udata/harvest/tests/test_base_backend.py +5 -4
  82. udata/harvest/tests/test_dcat_backend.py +50 -19
  83. udata/harvest/tests/test_models.py +2 -4
  84. udata/harvest/tests/test_notifications.py +2 -4
  85. udata/harvest/tests/test_tasks.py +2 -3
  86. udata/mail.py +90 -53
  87. udata/migrations/2025-01-05-dataservices-fields-changes.py +8 -14
  88. udata/migrations/2025-10-21-remove-ckan-harvest-modified-at.py +28 -0
  89. udata/migrations/2025-10-29-harvesters-sources-integrity.py +27 -0
  90. udata/mongo/taglist_field.py +3 -3
  91. udata/rdf.py +32 -15
  92. udata/sentry.py +3 -4
  93. udata/settings.py +7 -2
  94. udata/tags.py +5 -5
  95. udata/tasks.py +3 -3
  96. udata/templates/mail/message.html +65 -0
  97. udata/templates/mail/message.txt +16 -0
  98. udata/tests/__init__.py +40 -58
  99. udata/tests/api/__init__.py +87 -2
  100. udata/tests/api/test_activities_api.py +17 -23
  101. udata/tests/api/test_auth_api.py +2 -4
  102. udata/tests/api/test_contact_points.py +48 -54
  103. udata/tests/api/test_dataservices_api.py +57 -37
  104. udata/tests/api/test_datasets_api.py +146 -49
  105. udata/tests/api/test_me_api.py +4 -6
  106. udata/tests/api/test_organizations_api.py +19 -38
  107. udata/tests/api/test_reports_api.py +0 -4
  108. udata/tests/api/test_reuses_api.py +92 -19
  109. udata/tests/api/test_security_api.py +124 -0
  110. udata/tests/api/test_swagger.py +2 -3
  111. udata/tests/api/test_tags_api.py +6 -7
  112. udata/tests/api/test_transfer_api.py +0 -2
  113. udata/tests/api/test_user_api.py +8 -10
  114. udata/tests/apiv2/test_datasets.py +0 -4
  115. udata/tests/apiv2/test_me_api.py +0 -2
  116. udata/tests/apiv2/test_organizations.py +0 -2
  117. udata/tests/apiv2/test_swagger.py +2 -3
  118. udata/tests/apiv2/test_topics.py +0 -2
  119. udata/tests/cli/test_cli_base.py +14 -12
  120. udata/tests/cli/test_db_cli.py +51 -54
  121. udata/tests/contact_point/test_contact_point_models.py +2 -2
  122. udata/tests/dataservice/test_csv_adapter.py +2 -5
  123. udata/tests/dataservice/test_dataservice_rdf.py +8 -6
  124. udata/tests/dataservice/test_dataservice_tasks.py +36 -38
  125. udata/tests/dataset/test_csv_adapter.py +2 -5
  126. udata/tests/dataset/test_dataset_actions.py +2 -4
  127. udata/tests/dataset/test_dataset_commands.py +2 -4
  128. udata/tests/dataset/test_dataset_events.py +3 -3
  129. udata/tests/dataset/test_dataset_model.py +6 -7
  130. udata/tests/dataset/test_dataset_rdf.py +201 -12
  131. udata/tests/dataset/test_dataset_recommendations.py +2 -2
  132. udata/tests/dataset/test_dataset_tasks.py +66 -68
  133. udata/tests/dataset/test_resource_preview.py +39 -48
  134. udata/tests/dataset/test_transport_tasks.py +2 -2
  135. udata/tests/features/territories/__init__.py +0 -6
  136. udata/tests/features/territories/test_territories_api.py +25 -24
  137. udata/tests/forms/test_current_user_field.py +2 -2
  138. udata/tests/forms/test_dict_field.py +2 -4
  139. udata/tests/forms/test_extras_fields.py +2 -3
  140. udata/tests/forms/test_image_field.py +2 -2
  141. udata/tests/forms/test_model_field.py +2 -4
  142. udata/tests/forms/test_publish_as_field.py +2 -4
  143. udata/tests/forms/test_user_forms.py +26 -29
  144. udata/tests/frontend/test_auth.py +2 -3
  145. udata/tests/frontend/test_csv.py +5 -6
  146. udata/tests/frontend/test_error_handlers.py +2 -3
  147. udata/tests/frontend/test_hooks.py +5 -7
  148. udata/tests/frontend/test_markdown.py +3 -4
  149. udata/tests/helpers.py +2 -7
  150. udata/tests/metrics/test_metrics.py +52 -48
  151. udata/tests/metrics/test_tasks.py +154 -150
  152. udata/tests/organization/test_csv_adapter.py +2 -5
  153. udata/tests/organization/test_notifications.py +2 -4
  154. udata/tests/organization/test_organization_model.py +3 -4
  155. udata/tests/organization/test_organization_rdf.py +2 -8
  156. udata/tests/plugin.py +6 -110
  157. udata/tests/reuse/test_reuse_model.py +3 -4
  158. udata/tests/site/test_site_api.py +0 -2
  159. udata/tests/site/test_site_csv_exports.py +0 -2
  160. udata/tests/site/test_site_metrics.py +2 -4
  161. udata/tests/site/test_site_model.py +2 -2
  162. udata/tests/site/test_site_rdf.py +4 -7
  163. udata/tests/test_activity.py +3 -3
  164. udata/tests/test_api_fields.py +6 -9
  165. udata/tests/test_cors.py +0 -2
  166. udata/tests/test_dcat_commands.py +2 -3
  167. udata/tests/test_discussions.py +2 -7
  168. udata/tests/test_mail.py +150 -114
  169. udata/tests/test_migrations.py +413 -419
  170. udata/tests/test_model.py +10 -11
  171. udata/tests/test_notifications.py +2 -3
  172. udata/tests/test_owned.py +3 -3
  173. udata/tests/test_rdf.py +19 -15
  174. udata/tests/test_routing.py +5 -5
  175. udata/tests/test_storages.py +6 -5
  176. udata/tests/test_tags.py +2 -4
  177. udata/tests/test_topics.py +2 -4
  178. udata/tests/test_transfer.py +4 -5
  179. udata/tests/topic/test_topic_tasks.py +25 -27
  180. udata/tests/user/test_user_rdf.py +2 -8
  181. udata/tests/user/test_user_tasks.py +3 -5
  182. udata/tests/workers/test_jobs_commands.py +2 -2
  183. udata/tests/workers/test_tasks_routing.py +27 -27
  184. udata/translations/ar/LC_MESSAGES/udata.mo +0 -0
  185. udata/translations/ar/LC_MESSAGES/udata.po +369 -435
  186. udata/translations/de/LC_MESSAGES/udata.mo +0 -0
  187. udata/translations/de/LC_MESSAGES/udata.po +371 -437
  188. udata/translations/es/LC_MESSAGES/udata.mo +0 -0
  189. udata/translations/es/LC_MESSAGES/udata.po +369 -435
  190. udata/translations/fr/LC_MESSAGES/udata.mo +0 -0
  191. udata/translations/fr/LC_MESSAGES/udata.po +381 -447
  192. udata/translations/it/LC_MESSAGES/udata.mo +0 -0
  193. udata/translations/it/LC_MESSAGES/udata.po +371 -437
  194. udata/translations/pt/LC_MESSAGES/udata.mo +0 -0
  195. udata/translations/pt/LC_MESSAGES/udata.po +371 -437
  196. udata/translations/sr/LC_MESSAGES/udata.mo +0 -0
  197. udata/translations/sr/LC_MESSAGES/udata.po +372 -438
  198. udata/translations/udata.pot +379 -440
  199. udata/utils.py +14 -2
  200. {udata-12.0.2.dev15.dist-info → udata-13.0.1.dev21.dist-info}/METADATA +1 -2
  201. {udata-12.0.2.dev15.dist-info → udata-13.0.1.dev21.dist-info}/RECORD +205 -242
  202. udata/templates/mail/account_deleted.html +0 -5
  203. udata/templates/mail/account_deleted.txt +0 -6
  204. udata/templates/mail/account_inactivity.html +0 -40
  205. udata/templates/mail/account_inactivity.txt +0 -31
  206. udata/templates/mail/badge_added_association.html +0 -33
  207. udata/templates/mail/badge_added_association.txt +0 -11
  208. udata/templates/mail/badge_added_certified.html +0 -33
  209. udata/templates/mail/badge_added_certified.txt +0 -11
  210. udata/templates/mail/badge_added_company.html +0 -33
  211. udata/templates/mail/badge_added_company.txt +0 -11
  212. udata/templates/mail/badge_added_local_authority.html +0 -33
  213. udata/templates/mail/badge_added_local_authority.txt +0 -11
  214. udata/templates/mail/badge_added_public_service.html +0 -33
  215. udata/templates/mail/badge_added_public_service.txt +0 -11
  216. udata/templates/mail/discussion_closed.html +0 -47
  217. udata/templates/mail/discussion_closed.txt +0 -16
  218. udata/templates/mail/inactive_account_deleted.html +0 -5
  219. udata/templates/mail/inactive_account_deleted.txt +0 -6
  220. udata/templates/mail/membership_refused.html +0 -20
  221. udata/templates/mail/membership_refused.txt +0 -11
  222. udata/templates/mail/membership_request.html +0 -46
  223. udata/templates/mail/membership_request.txt +0 -12
  224. udata/templates/mail/new_discussion.html +0 -44
  225. udata/templates/mail/new_discussion.txt +0 -15
  226. udata/templates/mail/new_discussion_comment.html +0 -45
  227. udata/templates/mail/new_discussion_comment.txt +0 -16
  228. udata/templates/mail/new_member.html +0 -27
  229. udata/templates/mail/new_member.txt +0 -11
  230. udata/templates/mail/new_reuse.html +0 -37
  231. udata/templates/mail/new_reuse.txt +0 -9
  232. udata/templates/mail/test.html +0 -6
  233. udata/templates/mail/test.txt +0 -6
  234. udata/templates/mail/user_mail_card.html +0 -26
  235. udata/templates/security/email/base.html +0 -105
  236. udata/templates/security/email/base.txt +0 -6
  237. udata/templates/security/email/button.html +0 -3
  238. udata/templates/security/email/change_notice.html +0 -22
  239. udata/templates/security/email/change_notice.txt +0 -8
  240. udata/templates/security/email/confirmation_instructions.html +0 -20
  241. udata/templates/security/email/confirmation_instructions.txt +0 -7
  242. udata/templates/security/email/login_instructions.html +0 -19
  243. udata/templates/security/email/login_instructions.txt +0 -7
  244. udata/templates/security/email/reset_instructions.html +0 -24
  245. udata/templates/security/email/reset_instructions.txt +0 -9
  246. udata/templates/security/email/reset_notice.html +0 -11
  247. udata/templates/security/email/reset_notice.txt +0 -4
  248. udata/templates/security/email/welcome.html +0 -24
  249. udata/templates/security/email/welcome.txt +0 -9
  250. udata/templates/security/email/welcome_existing.html +0 -32
  251. udata/templates/security/email/welcome_existing.txt +0 -14
  252. udata/terms.md +0 -6
  253. udata/tests/frontend/__init__.py +0 -23
  254. udata/tests/metrics/conftest.py +0 -15
  255. {udata-12.0.2.dev15.dist-info → udata-13.0.1.dev21.dist-info}/WHEEL +0 -0
  256. {udata-12.0.2.dev15.dist-info → udata-13.0.1.dev21.dist-info}/entry_points.txt +0 -0
  257. {udata-12.0.2.dev15.dist-info → udata-13.0.1.dev21.dist-info}/licenses/LICENSE +0 -0
  258. {udata-12.0.2.dev15.dist-info → udata-13.0.1.dev21.dist-info}/top_level.txt +0 -0
@@ -1,4 +1,3 @@
1
- import pytest
2
1
  from flask import url_for
3
2
 
4
3
  from udata.core.contact_point.factories import ContactPointFactory
@@ -7,17 +6,12 @@ from udata.core.organization.factories import OrganizationFactory
7
6
  from udata.core.organization.models import Member
8
7
  from udata.i18n import gettext as _
9
8
  from udata.models import ContactPoint
9
+ from udata.tests.api import APITestCase
10
10
  from udata.tests.helpers import assert200, assert201, assert204, assert400, assert403
11
11
  from udata.utils import faker
12
12
 
13
- pytestmark = [
14
- pytest.mark.usefixtures("clean_db"),
15
- ]
16
-
17
-
18
- class ContactPointAPITest:
19
- modules = []
20
13
 
14
+ class ContactPointAPITest(APITestCase):
21
15
  def test_get_or_create(self):
22
16
  org = OrganizationFactory()
23
17
  contact_point, created = ContactPoint.objects().get_or_create(
@@ -51,46 +45,46 @@ class ContactPointAPITest:
51
45
  assert created
52
46
  assert contact_point.name == "Another"
53
47
 
54
- def test_contact_point_api_create(self, api):
55
- user = api.login()
48
+ def test_contact_point_api_create(self):
49
+ user = self.login()
56
50
  data = {
57
51
  "name": faker.word(),
58
52
  "email": faker.email(),
59
53
  "contact_form": faker.url(),
60
54
  "role": "contact",
61
55
  }
62
- response = api.post(url_for("api.contact_points"), data=data)
56
+ response = self.post(url_for("api.contact_points"), data=data)
63
57
  assert201(response)
64
58
  assert ContactPoint.objects.count() == 1
65
59
 
66
60
  contact_point = ContactPoint.objects.first()
67
61
  assert contact_point.owner.id == user.id
68
62
 
69
- def test_contact_point_api_create_email_or_contact_form(self, api):
70
- api.login()
63
+ def test_contact_point_api_create_email_or_contact_form(self):
64
+ self.login()
71
65
  data = {"name": faker.word(), "contact_form": faker.url(), "role": "contact"}
72
- response = api.post(url_for("api.contact_points"), data=data)
66
+ response = self.post(url_for("api.contact_points"), data=data)
73
67
  assert201(response)
74
68
  assert ContactPoint.objects.count() == 1
75
69
 
76
70
  data = {"name": faker.word(), "email": faker.email(), "role": "contact"}
77
- response = api.post(url_for("api.contact_points"), data=data)
71
+ response = self.post(url_for("api.contact_points"), data=data)
78
72
  assert201(response)
79
73
  assert ContactPoint.objects.count() == 2
80
74
 
81
- def test_contact_point_duplicate_creation(self, api):
82
- api.login()
75
+ def test_contact_point_duplicate_creation(self):
76
+ self.login()
83
77
  data = {"name": faker.word(), "contact_form": faker.url(), "role": "contact"}
84
- response = api.post(url_for("api.contact_points"), data=data)
78
+ response = self.post(url_for("api.contact_points"), data=data)
85
79
  assert201(response)
86
80
  assert ContactPoint.objects.count() == 1
87
81
 
88
- response = api.post(url_for("api.contact_points"), data=data)
82
+ response = self.post(url_for("api.contact_points"), data=data)
89
83
  assert200(response)
90
84
  assert ContactPoint.objects.count() == 1
91
85
 
92
- def test_contact_point_for_different_org(self, api):
93
- user = api.login()
86
+ def test_contact_point_for_different_org(self):
87
+ user = self.login()
94
88
  member = Member(user=user, role="editor")
95
89
  org_a = OrganizationFactory(members=[member])
96
90
 
@@ -100,11 +94,11 @@ class ContactPointAPITest:
100
94
  "role": "contact",
101
95
  "organization": str(org_a.id),
102
96
  }
103
- response = api.post(url_for("api.contact_points"), data=data)
97
+ response = self.post(url_for("api.contact_points"), data=data)
104
98
  assert201(response)
105
99
  assert ContactPoint.objects.count() == 1
106
100
 
107
- response = api.post(url_for("api.contact_points"), data=data)
101
+ response = self.post(url_for("api.contact_points"), data=data)
108
102
  assert200(response)
109
103
  assert ContactPoint.objects.count() == 1
110
104
 
@@ -114,39 +108,39 @@ class ContactPointAPITest:
114
108
 
115
109
  org_b = OrganizationFactory(members=[])
116
110
  data["organization"] = str(org_b.id)
117
- response = api.post(url_for("api.contact_points"), data=data)
111
+ response = self.post(url_for("api.contact_points"), data=data)
118
112
  assert400(response)
119
113
  assert ContactPoint.objects.count() == 1
120
114
 
121
115
  org_b.members = [Member(user=user, role="editor")]
122
116
  org_b.save()
123
117
 
124
- response = api.post(url_for("api.contact_points"), data=data)
118
+ response = self.post(url_for("api.contact_points"), data=data)
125
119
  assert201(response)
126
120
  assert ContactPoint.objects.count() == 2
127
121
 
128
- def test_contact_point_api_invalid_email(self, api):
129
- api.login()
122
+ def test_contact_point_api_invalid_email(self):
123
+ self.login()
130
124
  data = {"name": faker.word(), "email": faker.word(), "role": "contact"}
131
- response = api.post(url_for("api.contact_points"), data=data)
125
+ response = self.post(url_for("api.contact_points"), data=data)
132
126
  assert400(response)
133
127
  assert "email" in response.json["errors"]
134
128
  assert ContactPoint.objects.count() == 0
135
129
 
136
- def test_contact_point_missing_contact_information(self, api):
137
- api.login()
130
+ def test_contact_point_missing_contact_information(self):
131
+ self.login()
138
132
  data = {"name": faker.word(), "role": "contact"}
139
- response = api.post(url_for("api.contact_points"), data=data)
133
+ response = self.post(url_for("api.contact_points"), data=data)
140
134
  assert400(response)
141
135
  assert response.json["message"] == _(
142
136
  "At least an email or a contact form is required for a contact point"
143
137
  )
144
138
  assert ContactPoint.objects.count() == 0
145
139
 
146
- def test_contact_point_missing_role(self, api):
147
- api.login()
140
+ def test_contact_point_missing_role(self):
141
+ self.login()
148
142
  data = {"name": faker.word(), "email": faker.email()}
149
- response = api.post(url_for("api.contact_points"), data=data)
143
+ response = self.post(url_for("api.contact_points"), data=data)
150
144
  assert400(response)
151
145
  assert (
152
146
  response.json["message"]
@@ -154,70 +148,70 @@ class ContactPointAPITest:
154
148
  )
155
149
  assert ContactPoint.objects.count() == 0
156
150
 
157
- def test_contact_point_no_need_for_email_for_role_other_than_contact(self, api):
158
- api.login()
151
+ def test_contact_point_no_need_for_email_for_role_other_than_contact(self):
152
+ self.login()
159
153
  roles_other_than_contact = [role_ for role_ in CONTACT_ROLES.keys() if role_ != "contact"]
160
154
  for index, role in enumerate(roles_other_than_contact):
161
155
  data = {"name": faker.word(), "role": role}
162
- response = api.post(url_for("api.contact_points"), data=data)
156
+ response = self.post(url_for("api.contact_points"), data=data)
163
157
  assert201(response)
164
158
  assert ContactPoint.objects.count() == index + 1
165
159
 
166
- def test_contact_point_api_update(self, api):
167
- user = api.login()
160
+ def test_contact_point_api_update(self):
161
+ user = self.login()
168
162
  member = Member(user=user, role="editor")
169
163
  org = OrganizationFactory(members=[member])
170
164
  contact_point = ContactPointFactory(organization=org)
171
165
  data = contact_point.to_dict()
172
166
  data["email"] = "new.email@newdomain.com"
173
- response = api.put(url_for("api.contact_point", contact_point=contact_point), data)
167
+ response = self.put(url_for("api.contact_point", contact_point=contact_point), data)
174
168
  assert200(response)
175
169
  assert ContactPoint.objects.count() == 1
176
170
  assert ContactPoint.objects.first().email == "new.email@newdomain.com"
177
171
 
178
- def test_contact_point_api_update_to_existing_contact_point(self, api):
179
- user = api.login()
172
+ def test_contact_point_api_update_to_existing_contact_point(self):
173
+ user = self.login()
180
174
  contact_point_a = ContactPointFactory(email="a@example.org", owner=user)
181
175
  contact_point_b = ContactPointFactory(email="b@example.org", owner=user)
182
176
 
183
177
  data_b = contact_point_b.to_dict()
184
- response = api.put(url_for("api.contact_point", contact_point=contact_point_a), data_b)
178
+ response = self.put(url_for("api.contact_point", contact_point=contact_point_a), data_b)
185
179
  assert400(response)
186
180
  assert ContactPoint.objects.count() == 2
187
181
 
188
182
  contact_point_a.reload()
189
183
  assert contact_point_a.email == "a@example.org"
190
184
 
191
- def test_contact_point_api_update_forbidden(self, api):
192
- api.login()
185
+ def test_contact_point_api_update_forbidden(self):
186
+ self.login()
193
187
  org = OrganizationFactory()
194
188
  contact_point = ContactPointFactory(organization=org)
195
189
  data = contact_point.to_dict()
196
190
  data["email"] = "new.email@newdomain.com"
197
- response = api.put(url_for("api.contact_point", contact_point=contact_point), data)
191
+ response = self.put(url_for("api.contact_point", contact_point=contact_point), data)
198
192
  assert403(response)
199
193
  assert ContactPoint.objects.count() == 1
200
194
  assert ContactPoint.objects.first().email == contact_point.email
201
195
 
202
- def test_contact_point_api_delete(self, api):
203
- user = api.login()
196
+ def test_contact_point_api_delete(self):
197
+ user = self.login()
204
198
  member = Member(user=user, role="editor")
205
199
  org = OrganizationFactory(members=[member])
206
200
  contact_point = ContactPointFactory(organization=org)
207
- response = api.delete(url_for("api.contact_point", contact_point=contact_point))
201
+ response = self.delete(url_for("api.contact_point", contact_point=contact_point))
208
202
  assert204(response)
209
203
  assert ContactPoint.objects.count() == 0
210
204
 
211
- def test_contact_point_roles_list(self, api):
205
+ def test_contact_point_roles_list(self):
212
206
  """It should fetch the contact point roles list from the API"""
213
- response = api.get(url_for("api.contact_point_roles"))
207
+ response = self.get(url_for("api.contact_point_roles"))
214
208
  assert200(response)
215
209
  assert len(response.json) == len(CONTACT_ROLES)
216
210
 
217
- def test_contact_point_api_delete_forbidden(self, api):
218
- api.login()
211
+ def test_contact_point_api_delete_forbidden(self):
212
+ self.login()
219
213
  org = OrganizationFactory()
220
214
  contact_point = ContactPointFactory(organization=org)
221
- response = api.delete(url_for("api.contact_point", contact_point=contact_point))
215
+ response = self.delete(url_for("api.contact_point", contact_point=contact_point))
222
216
  assert403(response)
223
217
  assert ContactPoint.objects.count() == 1
@@ -6,21 +6,17 @@ from flask import url_for
6
6
  from werkzeug.test import TestResponse
7
7
 
8
8
  import udata.core.organization.constants as org_constants
9
- from udata.core.dataservices.constants import (
10
- DATASERVICE_ACCESS_AUDIENCE_ADMINISTRATION,
11
- DATASERVICE_ACCESS_AUDIENCE_COMPANY,
12
- DATASERVICE_ACCESS_AUDIENCE_UNDER_CONDITIONS,
13
- DATASERVICE_ACCESS_AUDIENCE_YES,
14
- DATASERVICE_ACCESS_TYPE_OPEN,
15
- DATASERVICE_ACCESS_TYPE_OPEN_WITH_ACCOUNT,
16
- DATASERVICE_ACCESS_TYPE_RESTRICTED,
9
+ from udata.core.access_type.constants import (
10
+ AccessAudienceCondition,
11
+ AccessAudienceType,
12
+ AccessType,
17
13
  )
18
14
  from udata.core.dataservices.factories import DataserviceFactory
19
15
  from udata.core.dataservices.models import Dataservice
20
16
  from udata.core.dataset.factories import DatasetFactory, LicenseFactory
21
17
  from udata.core.organization.factories import OrganizationFactory
22
18
  from udata.core.organization.models import Member
23
- from udata.core.topic.factories import TopicElementFactory, TopicFactory
19
+ from udata.core.topic.factories import ReuseFactory, TopicElementFactory, TopicFactory
24
20
  from udata.core.user.factories import AdminFactory, UserFactory
25
21
  from udata.i18n import gettext as _
26
22
  from udata.tests.helpers import assert200, assert400, assert410
@@ -34,8 +30,6 @@ def dataservice_in_response(response: TestResponse, dataservice: Dataservice) ->
34
30
 
35
31
 
36
32
  class DataserviceAPITest(APITestCase):
37
- modules = []
38
-
39
33
  def test_dataservice_api_get(self):
40
34
  """It should fetch a dataservice from the API"""
41
35
  dataservice = DataserviceFactory()
@@ -105,6 +99,34 @@ class DataserviceAPITest(APITestCase):
105
99
  assert len(response.json["data"]) == 1
106
100
  assert response.json["data"][0]["id"] == str(topic_dataservice.id)
107
101
 
102
+ # filter on reuse
103
+ reuse_dataservice = DataserviceFactory()
104
+ reuse = ReuseFactory(dataservices=[reuse_dataservice])
105
+ response = self.get(url_for("api.dataservices", reuse=reuse.id))
106
+ assert200(response)
107
+ assert len(response.json["data"]) == 1
108
+ assert response.json["data"][0]["id"] == str(reuse_dataservice.id)
109
+
110
+ def test_dataservices_topic_filter_errors(self):
111
+ # non-existing
112
+ response = self.get(url_for("api.dataservices", topic="690c7f48ec85adaa376c1e93"))
113
+ assert200(response)
114
+
115
+ # not an object ID
116
+ response = self.get(url_for("api.dataservices", topic="xxx"))
117
+ assert400(response)
118
+ assert "`topic` must be an identifier" in response.json["message"]
119
+
120
+ def test_dataservices_reuse_filter_errors(self):
121
+ # non-existing
122
+ response = self.get(url_for("api.dataservices", reuse="690c7f48ec85adaa376c1e93"))
123
+ assert200(response)
124
+
125
+ # not an object ID
126
+ response = self.get(url_for("api.dataservices", reuse="xxx"))
127
+ assert400(response)
128
+ assert "`reuse` must be an identifier" in response.json["message"]
129
+
108
130
  def test_dataservice_api_create(self):
109
131
  user = self.login()
110
132
  datasets = DatasetFactory.create_batch(3)
@@ -140,15 +162,15 @@ class DataserviceAPITest(APITestCase):
140
162
  "extras": {
141
163
  "foo": "bar",
142
164
  },
143
- "access_type": DATASERVICE_ACCESS_TYPE_RESTRICTED,
165
+ "access_type": AccessType.RESTRICTED,
144
166
  "access_audiences": [
145
167
  {
146
- "role": DATASERVICE_ACCESS_AUDIENCE_ADMINISTRATION,
147
- "condition": DATASERVICE_ACCESS_AUDIENCE_YES,
168
+ "role": AccessAudienceType.ADMINISTRATION,
169
+ "condition": AccessAudienceCondition.YES,
148
170
  },
149
171
  {
150
- "role": DATASERVICE_ACCESS_AUDIENCE_COMPANY,
151
- "condition": DATASERVICE_ACCESS_AUDIENCE_UNDER_CONDITIONS,
172
+ "role": AccessAudienceType.COMPANY,
173
+ "condition": AccessAudienceCondition.UNDER_CONDITIONS,
152
174
  },
153
175
  ],
154
176
  },
@@ -164,20 +186,18 @@ class DataserviceAPITest(APITestCase):
164
186
  self.assertEqual(
165
187
  response.json["self_api_url"], "http://local.test/api/1/dataservices/updated-title/"
166
188
  )
167
- self.assertEqual(response.json["access_type"], DATASERVICE_ACCESS_TYPE_RESTRICTED)
189
+ self.assertEqual(response.json["access_type"], AccessType.RESTRICTED)
168
190
  self.assertEqual(len(response.json["access_audiences"]), 2)
169
191
  self.assertEqual(
170
- response.json["access_audiences"][0]["role"], DATASERVICE_ACCESS_AUDIENCE_ADMINISTRATION
171
- )
172
- self.assertEqual(
173
- response.json["access_audiences"][0]["condition"], DATASERVICE_ACCESS_AUDIENCE_YES
192
+ response.json["access_audiences"][0]["role"], AccessAudienceType.ADMINISTRATION
174
193
  )
175
194
  self.assertEqual(
176
- response.json["access_audiences"][1]["role"], DATASERVICE_ACCESS_AUDIENCE_COMPANY
195
+ response.json["access_audiences"][0]["condition"], AccessAudienceCondition.YES
177
196
  )
197
+ self.assertEqual(response.json["access_audiences"][1]["role"], AccessAudienceType.COMPANY)
178
198
  self.assertEqual(
179
199
  response.json["access_audiences"][1]["condition"],
180
- DATASERVICE_ACCESS_AUDIENCE_UNDER_CONDITIONS,
200
+ AccessAudienceCondition.UNDER_CONDITIONS,
181
201
  )
182
202
  # metadata_modified_at should have been updated during the patch
183
203
  self.assertNotEqual(
@@ -326,7 +346,7 @@ class DataserviceAPITest(APITestCase):
326
346
  "title": "B",
327
347
  "base_api_url": "https://example.org/B",
328
348
  "datasets": [dataset_b.id],
329
- "access_type": DATASERVICE_ACCESS_TYPE_OPEN,
349
+ "access_type": AccessType.OPEN,
330
350
  },
331
351
  )
332
352
  self.post(
@@ -335,7 +355,7 @@ class DataserviceAPITest(APITestCase):
335
355
  "title": "C",
336
356
  "base_api_url": "https://example.org/C",
337
357
  "datasets": [dataset_a.id, dataset_b.id],
338
- "access_type": DATASERVICE_ACCESS_TYPE_OPEN_WITH_ACCOUNT,
358
+ "access_type": AccessType.OPEN_WITH_ACCOUNT,
339
359
  },
340
360
  )
341
361
  self.post(
@@ -344,7 +364,7 @@ class DataserviceAPITest(APITestCase):
344
364
  "title": "A",
345
365
  "base_api_url": "https://example.org/A",
346
366
  "datasets": [dataset_a.id],
347
- "access_type": DATASERVICE_ACCESS_TYPE_RESTRICTED,
367
+ "access_type": AccessType.RESTRICTED,
348
368
  },
349
369
  )
350
370
  self.post(
@@ -407,7 +427,7 @@ class DataserviceAPITest(APITestCase):
407
427
  self.assertEqual(response.json["data"][0]["title"], "A")
408
428
  self.assertEqual(response.json["data"][1]["title"], "C")
409
429
 
410
- response = self.get(url_for("api.dataservices", access_type=DATASERVICE_ACCESS_TYPE_OPEN))
430
+ response = self.get(url_for("api.dataservices", access_type=AccessType.OPEN))
411
431
  self.assert200(response)
412
432
 
413
433
  print(response.json)
@@ -598,15 +618,15 @@ class DataserviceAPITest(APITestCase):
598
618
  {
599
619
  "title": "My title",
600
620
  "base_api_url": "https://example.org",
601
- "access_type": DATASERVICE_ACCESS_TYPE_RESTRICTED,
621
+ "access_type": AccessType.RESTRICTED,
602
622
  "access_audiences": [
603
623
  {
604
- "role": DATASERVICE_ACCESS_AUDIENCE_ADMINISTRATION,
605
- "condition": DATASERVICE_ACCESS_AUDIENCE_YES,
624
+ "role": AccessAudienceType.ADMINISTRATION,
625
+ "condition": AccessAudienceCondition.YES,
606
626
  },
607
627
  {
608
- "role": DATASERVICE_ACCESS_AUDIENCE_ADMINISTRATION,
609
- "condition": DATASERVICE_ACCESS_AUDIENCE_UNDER_CONDITIONS,
628
+ "role": AccessAudienceType.ADMINISTRATION,
629
+ "condition": AccessAudienceCondition.UNDER_CONDITIONS,
610
630
  },
611
631
  ],
612
632
  },
@@ -622,15 +642,15 @@ class DataserviceAPITest(APITestCase):
622
642
  dataservice = DataserviceFactory(owner=user, organization=original_org)
623
643
 
624
644
  data = dataservice.to_dict()
625
- data["access_type"] = DATASERVICE_ACCESS_TYPE_RESTRICTED
645
+ data["access_type"] = AccessType.RESTRICTED
626
646
  data["access_audiences"] = [
627
647
  {
628
- "role": DATASERVICE_ACCESS_AUDIENCE_ADMINISTRATION,
629
- "condition": DATASERVICE_ACCESS_AUDIENCE_YES,
648
+ "role": AccessAudienceType.ADMINISTRATION,
649
+ "condition": AccessAudienceCondition.YES,
630
650
  },
631
651
  {
632
- "role": DATASERVICE_ACCESS_AUDIENCE_ADMINISTRATION,
633
- "condition": DATASERVICE_ACCESS_AUDIENCE_UNDER_CONDITIONS,
652
+ "role": AccessAudienceType.ADMINISTRATION,
653
+ "condition": AccessAudienceCondition.UNDER_CONDITIONS,
634
654
  },
635
655
  ]
636
656
  response = self.patch(url_for("api.dataservice", dataservice=dataservice), data)