udata 14.0.0__py3-none-any.whl → 14.5.1.dev6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of udata might be problematic. Click here for more details.

Files changed (152) hide show
  1. udata/api/__init__.py +2 -0
  2. udata/api_fields.py +35 -4
  3. udata/app.py +18 -20
  4. udata/auth/__init__.py +29 -6
  5. udata/auth/forms.py +2 -2
  6. udata/auth/views.py +13 -6
  7. udata/commands/dcat.py +1 -1
  8. udata/commands/serve.py +3 -11
  9. udata/commands/tests/test_fixtures.py +9 -9
  10. udata/core/access_type/api.py +1 -1
  11. udata/core/access_type/constants.py +12 -8
  12. udata/core/activity/api.py +5 -6
  13. udata/core/badges/tests/test_commands.py +6 -6
  14. udata/core/csv.py +5 -0
  15. udata/core/dataservices/api.py +8 -1
  16. udata/core/dataservices/apiv2.py +2 -5
  17. udata/core/dataservices/models.py +5 -2
  18. udata/core/dataservices/rdf.py +2 -1
  19. udata/core/dataservices/tasks.py +13 -2
  20. udata/core/dataset/api.py +10 -0
  21. udata/core/dataset/models.py +6 -6
  22. udata/core/dataset/permissions.py +31 -0
  23. udata/core/dataset/rdf.py +8 -2
  24. udata/core/dataset/tasks.py +23 -7
  25. udata/core/discussions/api.py +15 -1
  26. udata/core/discussions/models.py +6 -0
  27. udata/core/legal/__init__.py +0 -0
  28. udata/core/legal/mails.py +128 -0
  29. udata/core/organization/api.py +16 -5
  30. udata/core/organization/apiv2.py +2 -3
  31. udata/core/organization/mails.py +1 -1
  32. udata/core/organization/models.py +15 -2
  33. udata/core/organization/notifications.py +84 -0
  34. udata/core/organization/permissions.py +1 -1
  35. udata/core/organization/tasks.py +3 -0
  36. udata/core/pages/tests/test_api.py +32 -0
  37. udata/core/post/api.py +24 -69
  38. udata/core/post/models.py +84 -16
  39. udata/core/post/tests/test_api.py +24 -1
  40. udata/core/reports/api.py +18 -0
  41. udata/core/reports/models.py +42 -2
  42. udata/core/reuse/api.py +8 -0
  43. udata/core/reuse/apiv2.py +2 -5
  44. udata/core/reuse/models.py +1 -1
  45. udata/core/reuse/tasks.py +7 -0
  46. udata/core/spatial/forms.py +2 -2
  47. udata/core/topic/models.py +8 -2
  48. udata/core/user/api.py +10 -3
  49. udata/core/user/models.py +12 -2
  50. udata/features/notifications/api.py +7 -18
  51. udata/features/notifications/models.py +56 -0
  52. udata/features/notifications/tasks.py +25 -0
  53. udata/flask_mongoengine/engine.py +0 -4
  54. udata/flask_mongoengine/pagination.py +1 -1
  55. udata/frontend/markdown.py +2 -1
  56. udata/harvest/actions.py +21 -1
  57. udata/harvest/api.py +25 -8
  58. udata/harvest/backends/base.py +27 -1
  59. udata/harvest/backends/ckan/harvesters.py +11 -2
  60. udata/harvest/backends/dcat.py +4 -1
  61. udata/harvest/commands.py +33 -0
  62. udata/harvest/filters.py +17 -6
  63. udata/harvest/models.py +16 -0
  64. udata/harvest/permissions.py +27 -0
  65. udata/harvest/tests/ckan/test_ckan_backend.py +33 -0
  66. udata/harvest/tests/test_actions.py +58 -5
  67. udata/harvest/tests/test_api.py +276 -122
  68. udata/harvest/tests/test_base_backend.py +86 -1
  69. udata/harvest/tests/test_dcat_backend.py +81 -10
  70. udata/harvest/tests/test_filters.py +6 -0
  71. udata/i18n.py +1 -4
  72. udata/mail.py +19 -1
  73. udata/migrations/2025-10-31-create-membership-request-notifications.py +55 -0
  74. udata/migrations/2025-12-04-add-uuid-to-discussion-messages.py +28 -0
  75. udata/mongo/slug_fields.py +1 -1
  76. udata/rdf.py +58 -10
  77. udata/routing.py +2 -2
  78. udata/settings.py +11 -0
  79. udata/tasks.py +1 -0
  80. udata/templates/mail/message.html +5 -31
  81. udata/tests/__init__.py +27 -2
  82. udata/tests/api/__init__.py +108 -21
  83. udata/tests/api/test_activities_api.py +36 -0
  84. udata/tests/api/test_auth_api.py +121 -95
  85. udata/tests/api/test_base_api.py +7 -4
  86. udata/tests/api/test_datasets_api.py +50 -19
  87. udata/tests/api/test_organizations_api.py +192 -197
  88. udata/tests/api/test_reports_api.py +157 -0
  89. udata/tests/api/test_reuses_api.py +147 -147
  90. udata/tests/api/test_security_api.py +12 -12
  91. udata/tests/api/test_swagger.py +4 -4
  92. udata/tests/api/test_tags_api.py +8 -8
  93. udata/tests/api/test_user_api.py +1 -1
  94. udata/tests/apiv2/test_search.py +30 -0
  95. udata/tests/apiv2/test_swagger.py +4 -4
  96. udata/tests/cli/test_cli_base.py +8 -9
  97. udata/tests/dataservice/test_dataservice_tasks.py +29 -0
  98. udata/tests/dataset/test_dataset_commands.py +4 -4
  99. udata/tests/dataset/test_dataset_model.py +66 -26
  100. udata/tests/dataset/test_dataset_rdf.py +99 -5
  101. udata/tests/dataset/test_dataset_tasks.py +25 -0
  102. udata/tests/frontend/test_auth.py +58 -1
  103. udata/tests/frontend/test_csv.py +0 -3
  104. udata/tests/helpers.py +31 -27
  105. udata/tests/organization/test_notifications.py +67 -2
  106. udata/tests/plugin.py +6 -261
  107. udata/tests/search/test_search_integration.py +33 -0
  108. udata/tests/site/test_site_csv_exports.py +22 -10
  109. udata/tests/test_activity.py +9 -9
  110. udata/tests/test_api_fields.py +10 -0
  111. udata/tests/test_dcat_commands.py +2 -2
  112. udata/tests/test_discussions.py +5 -5
  113. udata/tests/test_legal_mails.py +359 -0
  114. udata/tests/test_migrations.py +21 -21
  115. udata/tests/test_notifications.py +15 -57
  116. udata/tests/test_notifications_task.py +43 -0
  117. udata/tests/test_owned.py +81 -1
  118. udata/tests/test_storages.py +25 -19
  119. udata/tests/test_topics.py +77 -61
  120. udata/tests/test_uris.py +33 -0
  121. udata/tests/workers/test_jobs_commands.py +23 -23
  122. udata/translations/ar/LC_MESSAGES/udata.mo +0 -0
  123. udata/translations/ar/LC_MESSAGES/udata.po +187 -108
  124. udata/translations/de/LC_MESSAGES/udata.mo +0 -0
  125. udata/translations/de/LC_MESSAGES/udata.po +187 -108
  126. udata/translations/es/LC_MESSAGES/udata.mo +0 -0
  127. udata/translations/es/LC_MESSAGES/udata.po +187 -108
  128. udata/translations/fr/LC_MESSAGES/udata.mo +0 -0
  129. udata/translations/fr/LC_MESSAGES/udata.po +188 -109
  130. udata/translations/it/LC_MESSAGES/udata.mo +0 -0
  131. udata/translations/it/LC_MESSAGES/udata.po +187 -108
  132. udata/translations/pt/LC_MESSAGES/udata.mo +0 -0
  133. udata/translations/pt/LC_MESSAGES/udata.po +187 -108
  134. udata/translations/sr/LC_MESSAGES/udata.mo +0 -0
  135. udata/translations/sr/LC_MESSAGES/udata.po +187 -108
  136. udata/translations/udata.pot +215 -106
  137. udata/uris.py +0 -2
  138. udata-14.5.1.dev6.dist-info/METADATA +109 -0
  139. {udata-14.0.0.dist-info → udata-14.5.1.dev6.dist-info}/RECORD +143 -140
  140. udata/core/post/forms.py +0 -30
  141. udata/flask_mongoengine/json.py +0 -38
  142. udata/templates/mail/base.html +0 -105
  143. udata/templates/mail/base.txt +0 -6
  144. udata/templates/mail/button.html +0 -3
  145. udata/templates/mail/layouts/1-column.html +0 -19
  146. udata/templates/mail/layouts/2-columns.html +0 -20
  147. udata/templates/mail/layouts/center-panel.html +0 -16
  148. udata-14.0.0.dist-info/METADATA +0 -132
  149. {udata-14.0.0.dist-info → udata-14.5.1.dev6.dist-info}/WHEEL +0 -0
  150. {udata-14.0.0.dist-info → udata-14.5.1.dev6.dist-info}/entry_points.txt +0 -0
  151. {udata-14.0.0.dist-info → udata-14.5.1.dev6.dist-info}/licenses/LICENSE +0 -0
  152. {udata-14.0.0.dist-info → udata-14.5.1.dev6.dist-info}/top_level.txt +0 -0
@@ -32,36 +32,36 @@ def reuse_in_response(response: TestResponse, reuse: Reuse) -> bool:
32
32
 
33
33
 
34
34
  class ReuseAPITest(PytestOnlyAPITestCase):
35
- def test_reuse_api_list(self, api):
35
+ def test_reuse_api_list(self):
36
36
  """It should fetch a reuse list from the API"""
37
37
  reuses = ReuseFactory.create_batch(3, visible=True)
38
38
 
39
- response = api.get(url_for("api.reuses"))
39
+ response = self.get(url_for("api.reuses"))
40
40
  assert200(response)
41
41
  assert len(response.json["data"]) == len(reuses)
42
42
 
43
- def test_reuse_api_list_with_sorts(self, api):
43
+ def test_reuse_api_list_with_sorts(self):
44
44
  ReuseFactory(title="A", created_at="2024-03-01")
45
45
  ReuseFactory(title="B", metrics={"views": 42}, created_at="2024-02-01")
46
46
  ReuseFactory(title="C", metrics={"views": 1337}, created_at="2024-05-01")
47
47
  ReuseFactory(title="D", created_at="2024-04-01")
48
48
 
49
- response = api.get(url_for("api.reuses", sort="views"))
49
+ response = self.get(url_for("api.reuses", sort="views"))
50
50
  assert200(response)
51
51
 
52
52
  assert [reuse["title"] for reuse in response.json["data"]] == ["A", "D", "B", "C"]
53
53
 
54
- response = api.get(url_for("api.reuses", sort="-views"))
54
+ response = self.get(url_for("api.reuses", sort="-views"))
55
55
  assert200(response)
56
56
 
57
57
  assert [reuse["title"] for reuse in response.json["data"]] == ["C", "B", "D", "A"]
58
58
 
59
- response = api.get(url_for("api.reuses", sort="created"))
59
+ response = self.get(url_for("api.reuses", sort="created"))
60
60
  assert200(response)
61
61
 
62
62
  assert [reuse["title"] for reuse in response.json["data"]] == ["B", "A", "D", "C"]
63
63
 
64
- def test_reuse_api_list_with_filters(self, api):
64
+ def test_reuse_api_list_with_filters(self):
65
65
  """Should filters reuses results based on query filters"""
66
66
  owner = UserFactory()
67
67
  org = OrganizationFactory()
@@ -81,96 +81,96 @@ class ReuseAPITest(PytestOnlyAPITestCase):
81
81
  type_reuse = ReuseFactory(topic="health", type="application")
82
82
 
83
83
  # filter on tag
84
- response = api.get(url_for("api.reuses", tag="my-tag"))
84
+ response = self.get(url_for("api.reuses", tag="my-tag"))
85
85
  assert200(response)
86
86
  assert len(response.json["data"]) == 1
87
87
  assert response.json["data"][0]["id"] == str(tag_reuse.id)
88
88
 
89
89
  # filter on featured
90
- response = api.get(url_for("api.reuses", featured="true"))
90
+ response = self.get(url_for("api.reuses", featured="true"))
91
91
  assert200(response)
92
92
  assert len(response.json["data"]) == 1
93
93
  assert response.json["data"][0]["id"] == str(featured_reuse.id)
94
94
 
95
- response = api.get(url_for("api.reuses", featured="false"))
95
+ response = self.get(url_for("api.reuses", featured="false"))
96
96
  assert200(response)
97
97
  # Keep only featured reuses (if any)
98
98
  data = [reuse for reuse in response.json["data"] if reuse["featured"]]
99
99
  assert len(data) == 0 # It did not return any featured reuse
100
100
 
101
101
  # filter on topic
102
- response = api.get(url_for("api.reuses", topic=topic_reuse.topic))
102
+ response = self.get(url_for("api.reuses", topic=topic_reuse.topic))
103
103
  assert200(response)
104
104
  assert len(response.json["data"]) == 1
105
105
  assert response.json["data"][0]["id"] == str(topic_reuse.id)
106
106
 
107
107
  # filter on type
108
- response = api.get(url_for("api.reuses", type=type_reuse.type))
108
+ response = self.get(url_for("api.reuses", type=type_reuse.type))
109
109
  assert200(response)
110
110
  assert len(response.json["data"]) == 1
111
111
  assert response.json["data"][0]["id"] == str(type_reuse.id)
112
112
 
113
113
  # filter on owner
114
- response = api.get(url_for("api.reuses", owner=owner.id))
114
+ response = self.get(url_for("api.reuses", owner=owner.id))
115
115
  assert200(response)
116
116
  assert len(response.json["data"]) == 1
117
117
  assert response.json["data"][0]["id"] == str(owner_reuse.id)
118
118
 
119
119
  # filter on organization
120
- response = api.get(url_for("api.reuses", organization=org.id))
120
+ response = self.get(url_for("api.reuses", organization=org.id))
121
121
  assert200(response)
122
122
  assert len(response.json["data"]) == 1
123
123
  assert response.json["data"][0]["id"] == str(org_reuse.id)
124
124
 
125
- response = api.get(url_for("api.reuses", owner="owner-id"))
125
+ response = self.get(url_for("api.reuses", owner="owner-id"))
126
126
  assert400(response)
127
127
 
128
- response = api.get(url_for("api.reuses", organization="org-id"))
128
+ response = self.get(url_for("api.reuses", organization="org-id"))
129
129
  assert400(response)
130
130
 
131
131
  # filter on organization badge
132
- response = api.get(url_for("api.reuses", organization_badge=org_constants.PUBLIC_SERVICE))
132
+ response = self.get(url_for("api.reuses", organization_badge=org_constants.PUBLIC_SERVICE))
133
133
  assert200(response)
134
134
  assert len(response.json["data"]) == 1
135
135
  assert response.json["data"][0]["id"] == str(org_reuse_public_service.id)
136
136
 
137
- response = api.get(url_for("api.reuses", organization_badge="bad-badge"))
137
+ response = self.get(url_for("api.reuses", organization_badge="bad-badge"))
138
138
  assert400(response)
139
139
 
140
- def test_reuse_api_list_filter_private(self, api) -> None:
140
+ def test_reuse_api_list_filter_private(self) -> None:
141
141
  """Should filters reuses results based on the `private` filter"""
142
142
  user = UserFactory()
143
143
  public_reuse: Reuse = ReuseFactory()
144
144
  private_reuse: Reuse = ReuseFactory(private=True, owner=user)
145
145
 
146
146
  # Only public reuses for non-authenticated user.
147
- response: TestResponse = api.get(url_for("api.reuses"))
147
+ response: TestResponse = self.get(url_for("api.reuses"))
148
148
  assert200(response)
149
149
  assert len(response.json["data"]) == 1
150
150
  assert reuse_in_response(response, public_reuse)
151
151
 
152
152
  # With an authenticated user.
153
- api.login(user)
153
+ self.login(user)
154
154
  # all the reuses (by default)
155
- response = api.get(url_for("api.reuses"))
155
+ response = self.get(url_for("api.reuses"))
156
156
  assert200(response)
157
157
  assert len(response.json["data"]) == 2 # Return everything
158
158
  assert reuse_in_response(response, public_reuse)
159
159
  assert reuse_in_response(response, private_reuse)
160
160
 
161
161
  # only public
162
- response = api.get(url_for("api.reuses", private="false"))
162
+ response = self.get(url_for("api.reuses", private="false"))
163
163
  assert200(response)
164
164
  assert len(response.json["data"]) == 1 # Don't return the private reuse
165
165
  assert reuse_in_response(response, public_reuse)
166
166
 
167
167
  # only private
168
- response = api.get(url_for("api.reuses", private="true"))
168
+ response = self.get(url_for("api.reuses", private="true"))
169
169
  assert200(response)
170
170
  assert len(response.json["data"]) == 1 # Return only the private
171
171
  assert reuse_in_response(response, private_reuse)
172
172
 
173
- def test_reuse_api_list_filter_private_only_owned_by_user(self, api) -> None:
173
+ def test_reuse_api_list_filter_private_only_owned_by_user(self) -> None:
174
174
  """Should only return private reuses that are owned."""
175
175
  user = UserFactory()
176
176
  member = Member(user=user, role="editor")
@@ -180,13 +180,13 @@ class ReuseAPITest(PytestOnlyAPITestCase):
180
180
  private_not_owned: Reuse = ReuseFactory(private=True)
181
181
 
182
182
  # Only public reuses for non-authenticated user.
183
- response: TestResponse = api.get(url_for("api.reuses"))
183
+ response: TestResponse = self.get(url_for("api.reuses"))
184
184
  assert200(response)
185
185
  assert len(response.json["data"]) == 0
186
186
 
187
187
  # With an authenticated user.
188
- api.login(user)
189
- response = api.get(url_for("api.reuses"))
188
+ self.login(user)
189
+ response = self.get(url_for("api.reuses"))
190
190
  assert200(response)
191
191
  assert len(response.json["data"]) == 2 # Only the owned reuses
192
192
  assert reuse_in_response(response, private_owned)
@@ -194,19 +194,19 @@ class ReuseAPITest(PytestOnlyAPITestCase):
194
194
  assert not reuse_in_response(response, private_not_owned)
195
195
 
196
196
  # Still no private returned if `private=False`
197
- response = api.get(url_for("api.reuses", private=False))
197
+ response = self.get(url_for("api.reuses", private=False))
198
198
  assert200(response)
199
199
  assert len(response.json["data"]) == 0
200
200
 
201
201
  # Still only return owned private reuses
202
- response = api.get(url_for("api.reuses", private=True))
202
+ response = self.get(url_for("api.reuses", private=True))
203
203
  assert200(response)
204
204
  assert len(response.json["data"]) == 2 # Only the owned reuses
205
205
  assert reuse_in_response(response, private_owned)
206
206
  assert reuse_in_response(response, private_owned_through_org)
207
207
  assert not reuse_in_response(response, private_not_owned)
208
208
 
209
- def test_reuse_api_list_filter_private_only_owned_by_user_no_user(self, api) -> None:
209
+ def test_reuse_api_list_filter_private_only_owned_by_user_no_user(self) -> None:
210
210
  """Shouldn't return any private reuses for non logged in users."""
211
211
  user = UserFactory()
212
212
  member = Member(user=user, role="editor")
@@ -217,63 +217,63 @@ class ReuseAPITest(PytestOnlyAPITestCase):
217
217
  _private_owned_through_org: Reuse = ReuseFactory(private=True, organization=org)
218
218
  _private_not_owned: Reuse = ReuseFactory(private=True)
219
219
 
220
- response: TestResponse = api.get(url_for("api.reuses"))
220
+ response: TestResponse = self.get(url_for("api.reuses"))
221
221
  assert200(response)
222
222
  assert len(response.json["data"]) == 2
223
223
  assert reuse_in_response(response, public_owned)
224
224
  assert reuse_in_response(response, public_not_owned)
225
225
 
226
226
  # Still no private returned if `private=False`
227
- response = api.get(url_for("api.reuses", private=False))
227
+ response = self.get(url_for("api.reuses", private=False))
228
228
  assert200(response)
229
229
  assert len(response.json["data"]) == 2
230
230
  assert reuse_in_response(response, public_owned)
231
231
  assert reuse_in_response(response, public_not_owned)
232
232
 
233
233
  # Still no private returned if `private=True`
234
- response = api.get(url_for("api.reuses", private=True))
234
+ response = self.get(url_for("api.reuses", private=True))
235
235
  assert200(response)
236
236
  assert len(response.json["data"]) == 0
237
237
 
238
- def test_reuse_api_get(self, api):
238
+ def test_reuse_api_get(self):
239
239
  """It should fetch a reuse from the API"""
240
240
  reuse = ReuseFactory()
241
- response = api.get(url_for("api.reuse", reuse=reuse))
241
+ response = self.get(url_for("api.reuse", reuse=reuse))
242
242
  assert200(response)
243
243
 
244
- def test_reuse_api_get_deleted(self, api):
244
+ def test_reuse_api_get_deleted(self):
245
245
  """It should not fetch a deleted reuse from the API and raise 410"""
246
246
  reuse = ReuseFactory(deleted=datetime.utcnow())
247
- response = api.get(url_for("api.reuse", reuse=reuse))
247
+ response = self.get(url_for("api.reuse", reuse=reuse))
248
248
  assert410(response)
249
249
 
250
- def test_reuse_api_get_deleted_but_authorized(self, api):
250
+ def test_reuse_api_get_deleted_but_authorized(self):
251
251
  """It should fetch a deleted reuse from the API if authorized"""
252
- user = api.login()
252
+ user = self.login()
253
253
  reuse = ReuseFactory(deleted=datetime.utcnow(), owner=user)
254
- response = api.get(url_for("api.reuse", reuse=reuse))
254
+ response = self.get(url_for("api.reuse", reuse=reuse))
255
255
  assert200(response)
256
256
 
257
- def test_reuse_api_get_private(self, api):
257
+ def test_reuse_api_get_private(self):
258
258
  """It should not fetch a private reuse from the API and raise 404"""
259
259
  reuse = ReuseFactory(private=True)
260
260
 
261
- response = api.get(url_for("api.reuse", reuse=reuse))
261
+ response = self.get(url_for("api.reuse", reuse=reuse))
262
262
  assert404(response)
263
263
 
264
- def test_reuse_api_get_private_but_authorized(self, api):
264
+ def test_reuse_api_get_private_but_authorized(self):
265
265
  """It should fetch a private reuse from the API if user is authorized"""
266
- user = api.login()
266
+ user = self.login()
267
267
  reuse = ReuseFactory(owner=user, private=True)
268
268
 
269
- response = api.get(url_for("api.reuse", reuse=reuse))
269
+ response = self.get(url_for("api.reuse", reuse=reuse))
270
270
  assert200(response)
271
271
 
272
- def test_reuse_api_create(self, api):
272
+ def test_reuse_api_create(self):
273
273
  """It should create a reuse from the API"""
274
274
  data = ReuseFactory.as_dict()
275
- user = api.login()
276
- response = api.post(url_for("api.reuses"), data)
275
+ user = self.login()
276
+ response = self.post(url_for("api.reuses"), data)
277
277
  assert201(response)
278
278
  assert Reuse.objects.count() == 1
279
279
 
@@ -281,14 +281,14 @@ class ReuseAPITest(PytestOnlyAPITestCase):
281
281
  assert reuse.owner == user
282
282
  assert reuse.organization is None
283
283
 
284
- def test_reuse_api_create_as_org(self, api):
284
+ def test_reuse_api_create_as_org(self):
285
285
  """It should create a reuse as organization from the API"""
286
- user = api.login()
286
+ user = self.login()
287
287
  data = ReuseFactory.as_dict()
288
288
  member = Member(user=user, role="editor")
289
289
  org = OrganizationFactory(members=[member])
290
290
  data["organization"] = str(org.id)
291
- response = api.post(url_for("api.reuses"), data)
291
+ response = self.post(url_for("api.reuses"), data)
292
292
  assert201(response)
293
293
  assert Reuse.objects.count() == 1
294
294
 
@@ -296,43 +296,43 @@ class ReuseAPITest(PytestOnlyAPITestCase):
296
296
  assert reuse.owner is None
297
297
  assert reuse.organization == org
298
298
 
299
- def test_reuse_api_create_as_permissions(self, api):
299
+ def test_reuse_api_create_as_permissions(self):
300
300
  """It should create a reuse as organization from the API
301
301
 
302
302
  only if user is member.
303
303
  """
304
- api.login()
304
+ self.login()
305
305
  data = ReuseFactory.as_dict()
306
306
  org = OrganizationFactory()
307
307
  data["organization"] = str(org.id)
308
- response = api.post(url_for("api.reuses"), data)
308
+ response = self.post(url_for("api.reuses"), data)
309
309
  assert400(response)
310
310
  assert Reuse.objects.count() == 0
311
311
 
312
- def test_reuse_api_update(self, api):
312
+ def test_reuse_api_update(self):
313
313
  """It should update a reuse from the API"""
314
- user = api.login()
314
+ user = self.login()
315
315
  reuse = ReuseFactory(owner=user)
316
316
  data = reuse.to_dict()
317
317
  data["description"] = "new description"
318
- response = api.put(url_for("api.reuse", reuse=reuse), data)
318
+ response = self.put(url_for("api.reuse", reuse=reuse), data)
319
319
  assert200(response)
320
320
  assert Reuse.objects.count() == 1
321
321
  assert Reuse.objects.first().description == "new description"
322
322
 
323
- def test_reuse_api_remove_org(self, api):
324
- user = api.login()
323
+ def test_reuse_api_remove_org(self):
324
+ user = self.login()
325
325
  reuse = ReuseFactory(owner=user)
326
326
  data = reuse.to_dict()
327
327
  data["organization"] = None
328
- response = api.put(url_for("api.reuse", reuse=reuse), data)
328
+ response = self.put(url_for("api.reuse", reuse=reuse), data)
329
329
  assert200(response)
330
330
  assert Reuse.objects.count() == 1
331
331
  assert Reuse.objects.first().organization is None
332
332
 
333
- def test_reuse_api_update_org_with_full_object(self, api):
333
+ def test_reuse_api_update_org_with_full_object(self):
334
334
  """We can send the full org object (not only the ID) to update to an org"""
335
- user = api.login()
335
+ user = self.login()
336
336
  member = Member(user=user, role="admin")
337
337
  org = OrganizationFactory(members=[member])
338
338
  reuse = ReuseFactory(organization=org)
@@ -341,66 +341,66 @@ class ReuseAPITest(PytestOnlyAPITestCase):
341
341
  data["owner"] = None
342
342
  data["organization"] = org.to_dict()
343
343
 
344
- response = api.put(url_for("api.reuse", reuse=reuse), data)
344
+ response = self.put(url_for("api.reuse", reuse=reuse), data)
345
345
  assert200(response)
346
346
 
347
347
  assert Reuse.objects.count() == 1
348
348
  assert Reuse.objects.first().owner is None
349
349
  assert Reuse.objects.first().organization.id == org.id
350
350
 
351
- def test_reuse_api_update_deleted(self, api):
351
+ def test_reuse_api_update_deleted(self):
352
352
  """It should not update a deleted reuse from the API and raise 410"""
353
- api.login()
353
+ self.login()
354
354
  reuse = ReuseFactory(deleted=datetime.utcnow())
355
- response = api.put(url_for("api.reuse", reuse=reuse), {})
355
+ response = self.put(url_for("api.reuse", reuse=reuse), {})
356
356
  assert410(response)
357
357
 
358
- def test_reuse_api_delete(self, api):
358
+ def test_reuse_api_delete(self):
359
359
  """It should delete a reuse from the API"""
360
- user = api.login()
360
+ user = self.login()
361
361
  reuse = ReuseFactory(owner=user)
362
- response = api.delete(url_for("api.reuse", reuse=reuse))
362
+ response = self.delete(url_for("api.reuse", reuse=reuse))
363
363
  assert204(response)
364
364
  assert Reuse.objects.count() == 1
365
365
  assert Reuse.objects[0].deleted is not None
366
366
 
367
- response = api.put(url_for("api.reuse", reuse=reuse), {"deleted": None})
367
+ response = self.put(url_for("api.reuse", reuse=reuse), {"deleted": None})
368
368
  assert200(response)
369
369
  assert Reuse.objects.count() == 1
370
370
  assert Reuse.objects[0].deleted is None
371
371
 
372
- def test_reuse_api_delete_deleted(self, api):
372
+ def test_reuse_api_delete_deleted(self):
373
373
  """It should not delete a deleted reuse from the API and raise 410"""
374
- api.login()
374
+ self.login()
375
375
  reuse = ReuseFactory(deleted=datetime.utcnow())
376
- response = api.delete(url_for("api.reuse", reuse=reuse))
376
+ response = self.delete(url_for("api.reuse", reuse=reuse))
377
377
  assert410(response)
378
378
 
379
- def test_reuse_api_filter_by_dataset(self, api):
380
- user = api.login()
379
+ def test_reuse_api_filter_by_dataset(self):
380
+ user = self.login()
381
381
  dataset = DatasetFactory()
382
382
  other_dataset = DatasetFactory()
383
383
  ReuseFactory(owner=user, datasets=[dataset])
384
384
 
385
- response = api.get(url_for("api.reuses", dataset=dataset.id))
385
+ response = self.get(url_for("api.reuses", dataset=dataset.id))
386
386
  assert200(response)
387
387
  assert response.json["total"] == 1
388
388
  assert len(response.json["data"][0]["datasets"]) == 1
389
389
  assert response.json["data"][0]["datasets"][0]["title"] == dataset.title
390
390
 
391
- response = api.get(url_for("api.reuses", dataset=other_dataset.id))
391
+ response = self.get(url_for("api.reuses", dataset=other_dataset.id))
392
392
  assert200(response)
393
393
  assert response.json["total"] == 0
394
394
 
395
- def test_reuse_api_add_dataset(self, api):
395
+ def test_reuse_api_add_dataset(self):
396
396
  """It should add a dataset to a reuse from the API"""
397
- user = api.login()
397
+ user = self.login()
398
398
  reuse = ReuseFactory(owner=user)
399
399
 
400
400
  dataset = DatasetFactory()
401
401
  data = {"id": dataset.id, "class": "Dataset"}
402
402
  url = url_for("api.reuse_add_dataset", reuse=reuse)
403
- response = api.post(url, data)
403
+ response = self.post(url, data)
404
404
  assert201(response)
405
405
  reuse.reload()
406
406
  assert len(reuse.datasets) == 1
@@ -409,64 +409,64 @@ class ReuseAPITest(PytestOnlyAPITestCase):
409
409
  dataset = DatasetFactory()
410
410
  data = {"id": dataset.id, "class": "Dataset"}
411
411
  url = url_for("api.reuse_add_dataset", reuse=reuse)
412
- response = api.post(url, data)
412
+ response = self.post(url, data)
413
413
  assert201(response)
414
414
  reuse.reload()
415
415
  assert len(reuse.datasets) == 2
416
416
  assert reuse.datasets[-1] == dataset
417
417
 
418
- def test_reuse_api_add_dataset_twice(self, api):
418
+ def test_reuse_api_add_dataset_twice(self):
419
419
  """It should not add twice a dataset to a reuse from the API"""
420
- user = api.login()
420
+ user = self.login()
421
421
  dataset = DatasetFactory()
422
422
  reuse = ReuseFactory(owner=user, datasets=[dataset])
423
423
 
424
424
  data = {"id": dataset.id, "class": "Dataset"}
425
425
  url = url_for("api.reuse_add_dataset", reuse=reuse)
426
- response = api.post(url, data)
426
+ response = self.post(url, data)
427
427
  assert200(response)
428
428
  reuse.reload()
429
429
  assert len(reuse.datasets) == 1
430
430
  assert reuse.datasets[-1] == dataset
431
431
 
432
- def test_reuse_api_add_dataset_not_found(self, api):
432
+ def test_reuse_api_add_dataset_not_found(self):
433
433
  """It should return 404 when adding an unknown dataset to a reuse"""
434
- user = api.login()
434
+ user = self.login()
435
435
  reuse = ReuseFactory(owner=user)
436
436
 
437
437
  data = {"id": "not-found", "class": "Dataset"}
438
438
  url = url_for("api.reuse_add_dataset", reuse=reuse)
439
- response = api.post(url, data)
439
+ response = self.post(url, data)
440
440
 
441
441
  assert404(response)
442
442
  reuse.reload()
443
443
  assert len(reuse.datasets) == 0
444
444
 
445
- def test_reuse_api_filter_by_dataservice(self, api):
446
- user = api.login()
445
+ def test_reuse_api_filter_by_dataservice(self):
446
+ user = self.login()
447
447
  dataservice = DataserviceFactory()
448
448
  other_dataservice = DataserviceFactory()
449
449
  ReuseFactory(owner=user, dataservices=[dataservice])
450
450
 
451
- response = api.get(url_for("api.reuses", dataservice=dataservice.id))
451
+ response = self.get(url_for("api.reuses", dataservice=dataservice.id))
452
452
  assert200(response)
453
453
  assert response.json["total"] == 1
454
454
  assert len(response.json["data"][0]["dataservices"]) == 1
455
455
  assert response.json["data"][0]["dataservices"][0]["title"] == dataservice.title
456
456
 
457
- response = api.get(url_for("api.reuses", dataservice=other_dataservice.id))
457
+ response = self.get(url_for("api.reuses", dataservice=other_dataservice.id))
458
458
  assert200(response)
459
459
  assert response.json["total"] == 0
460
460
 
461
- def test_reuse_api_add_dataservice(self, api):
461
+ def test_reuse_api_add_dataservice(self):
462
462
  """It should add a dataset to a reuse from the API"""
463
- user = api.login()
463
+ user = self.login()
464
464
  reuse = ReuseFactory(owner=user)
465
465
 
466
466
  dataservice = DataserviceFactory()
467
467
  data = {"id": dataservice.id, "class": "Dataservice"}
468
468
  url = url_for("api.reuse_add_dataservice", reuse=reuse)
469
- response = api.post(url, data)
469
+ response = self.post(url, data)
470
470
  assert201(response)
471
471
  reuse.reload()
472
472
  assert len(reuse.dataservices) == 1
@@ -475,89 +475,89 @@ class ReuseAPITest(PytestOnlyAPITestCase):
475
475
  dataservice = DataserviceFactory()
476
476
  data = {"id": dataservice.id, "class": "dataservice"}
477
477
  url = url_for("api.reuse_add_dataservice", reuse=reuse)
478
- response = api.post(url, data)
478
+ response = self.post(url, data)
479
479
  assert201(response)
480
480
  reuse.reload()
481
481
  assert len(reuse.dataservices) == 2
482
482
  assert reuse.dataservices[-1] == dataservice
483
483
 
484
- def test_reuse_api_add_dataservice_twice(self, api):
484
+ def test_reuse_api_add_dataservice_twice(self):
485
485
  """It should not add twice a dataservice to a reuse from the API"""
486
- user = api.login()
486
+ user = self.login()
487
487
  dataservice = DataserviceFactory()
488
488
  reuse = ReuseFactory(owner=user, dataservices=[dataservice])
489
489
 
490
490
  data = {"id": dataservice.id, "class": "Dataservice"}
491
491
  url = url_for("api.reuse_add_dataservice", reuse=reuse)
492
- response = api.post(url, data)
492
+ response = self.post(url, data)
493
493
  assert200(response)
494
494
  reuse.reload()
495
495
  assert len(reuse.dataservices) == 1
496
496
  assert reuse.dataservices[-1] == dataservice
497
497
 
498
- def test_reuse_api_add_dataservice_not_found(self, api):
498
+ def test_reuse_api_add_dataservice_not_found(self):
499
499
  """It should return 404 when adding an unknown dataservice to a reuse"""
500
- user = api.login()
500
+ user = self.login()
501
501
  reuse = ReuseFactory(owner=user)
502
502
 
503
503
  data = {"id": "not-found", "class": "Dataservice"}
504
504
  url = url_for("api.reuse_add_dataservice", reuse=reuse)
505
- response = api.post(url, data)
505
+ response = self.post(url, data)
506
506
 
507
507
  assert404(response)
508
508
  reuse.reload()
509
509
  assert len(reuse.dataservices) == 0
510
510
 
511
- def test_reuse_api_feature(self, api):
511
+ def test_reuse_api_feature(self):
512
512
  """It should mark the reuse featured on POST"""
513
513
  reuse = ReuseFactory(featured=False)
514
514
 
515
- with api.user(AdminFactory()):
516
- response = api.post(url_for("api.reuse_featured", reuse=reuse))
515
+ with self.api_user(AdminFactory()):
516
+ response = self.post(url_for("api.reuse_featured", reuse=reuse))
517
517
  assert200(response)
518
518
 
519
519
  reuse.reload()
520
520
  assert reuse.featured
521
521
 
522
- def test_reuse_api_feature_already(self, api):
522
+ def test_reuse_api_feature_already(self):
523
523
  """It shouldn't do anything to feature an already featured reuse"""
524
524
  reuse = ReuseFactory(featured=True)
525
525
 
526
- with api.user(AdminFactory()):
527
- response = api.post(url_for("api.reuse_featured", reuse=reuse))
526
+ with self.api_user(AdminFactory()):
527
+ response = self.post(url_for("api.reuse_featured", reuse=reuse))
528
528
  assert200(response)
529
529
 
530
530
  reuse.reload()
531
531
  assert reuse.featured
532
532
 
533
- def test_reuse_api_unfeature(self, api):
533
+ def test_reuse_api_unfeature(self):
534
534
  """It should mark the reuse featured on POST"""
535
535
  reuse = ReuseFactory(featured=True)
536
536
 
537
- with api.user(AdminFactory()):
538
- response = api.delete(url_for("api.reuse_featured", reuse=reuse))
537
+ with self.api_user(AdminFactory()):
538
+ response = self.delete(url_for("api.reuse_featured", reuse=reuse))
539
539
  assert200(response)
540
540
 
541
541
  reuse.reload()
542
542
  assert not reuse.featured
543
543
 
544
- def test_reuse_api_unfeature_already(self, api):
544
+ def test_reuse_api_unfeature_already(self):
545
545
  """It shouldn't do anything to unfeature a not featured reuse"""
546
546
  reuse = ReuseFactory(featured=False)
547
547
 
548
- with api.user(AdminFactory()):
549
- response = api.delete(url_for("api.reuse_featured", reuse=reuse))
548
+ with self.api_user(AdminFactory()):
549
+ response = self.delete(url_for("api.reuse_featured", reuse=reuse))
550
550
  assert200(response)
551
551
 
552
552
  reuse.reload()
553
553
  assert not reuse.featured
554
554
 
555
- def test_follow_reuse(self, api):
555
+ def test_follow_reuse(self):
556
556
  """It should follow a reuse on POST"""
557
- user = api.login()
557
+ user = self.login()
558
558
  to_follow = ReuseFactory()
559
559
 
560
- response = api.post(url_for("api.reuse_followers", id=to_follow.id))
560
+ response = self.post(url_for("api.reuse_followers", id=to_follow.id))
561
561
  assert201(response)
562
562
 
563
563
  to_follow.count_followers()
@@ -570,13 +570,13 @@ class ReuseAPITest(PytestOnlyAPITestCase):
570
570
  assert Follow.objects.following(user).count() == 1
571
571
  assert Follow.objects.followers(user).count() == 0
572
572
 
573
- def test_unfollow_reuse(self, api):
573
+ def test_unfollow_reuse(self):
574
574
  """It should unfollow the reuse on DELETE"""
575
- user = api.login()
575
+ user = self.login()
576
576
  to_follow = ReuseFactory()
577
577
  Follow.objects.create(follower=user, following=to_follow)
578
578
 
579
- response = api.delete(url_for("api.reuse_followers", id=to_follow.id))
579
+ response = self.delete(url_for("api.reuse_followers", id=to_follow.id))
580
580
  assert200(response)
581
581
 
582
582
  nb_followers = Follow.objects.followers(to_follow).count()
@@ -588,7 +588,7 @@ class ReuseAPITest(PytestOnlyAPITestCase):
588
588
  assert Follow.objects.following(user).count() == 0
589
589
  assert Follow.objects.followers(user).count() == 0
590
590
 
591
- def test_suggest_reuses_api(self, api):
591
+ def test_suggest_reuses_api(self):
592
592
  """It should suggest reuses"""
593
593
  for i in range(3):
594
594
  ReuseFactory(
@@ -600,7 +600,7 @@ class ReuseAPITest(PytestOnlyAPITestCase):
600
600
  title="arealtestprefix-4", visible=True, metrics={"followers": 10}
601
601
  )
602
602
 
603
- response = api.get(url_for("api.suggest_reuses", q="arealtestpref", size=5))
603
+ response = self.get(url_for("api.suggest_reuses", q="arealtestpref", size=5))
604
604
  assert200(response)
605
605
 
606
606
  assert len(response.json) <= 5
@@ -614,12 +614,12 @@ class ReuseAPITest(PytestOnlyAPITestCase):
614
614
  assert "test" in suggestion["title"]
615
615
  assert response.json[0]["id"] == str(max_follower_reuse.id)
616
616
 
617
- def test_suggest_reuses_api_unicode(self, api):
617
+ def test_suggest_reuses_api_unicode(self):
618
618
  """It should suggest reuses with special characters"""
619
619
  for i in range(4):
620
620
  ReuseFactory(title="testé-{0}".format(i) if i % 2 else faker.word(), visible=True)
621
621
 
622
- response = api.get(url_for("api.suggest_reuses", q="testé", size=5))
622
+ response = self.get(url_for("api.suggest_reuses", q="testé", size=5))
623
623
  assert200(response)
624
624
 
625
625
  assert len(response.json) <= 5
@@ -632,18 +632,18 @@ class ReuseAPITest(PytestOnlyAPITestCase):
632
632
  assert "image_url" in suggestion
633
633
  assert "test" in suggestion["title"]
634
634
 
635
- def test_suggest_reuses_api_no_match(self, api):
635
+ def test_suggest_reuses_api_no_match(self):
636
636
  """It should not provide reuse suggestion if no match"""
637
637
  ReuseFactory.create_batch(3, visible=True)
638
638
 
639
- response = api.get(url_for("api.suggest_reuses", q="xxxxxx", size=5))
639
+ response = self.get(url_for("api.suggest_reuses", q="xxxxxx", size=5))
640
640
  assert200(response)
641
641
  assert len(response.json) == 0
642
642
 
643
- def test_suggest_reuses_api_empty(self, api):
643
+ def test_suggest_reuses_api_empty(self):
644
644
  """It should not provide reuse suggestion if no data"""
645
645
  # self.init_search()
646
- response = api.get(url_for("api.suggest_reuses", q="xxxxxx", size=5))
646
+ response = self.get(url_for("api.suggest_reuses", q="xxxxxx", size=5))
647
647
  assert200(response)
648
648
  assert len(response.json) == 0
649
649
 
@@ -709,76 +709,76 @@ class ReusesFeedAPItest(APITestCase):
709
709
 
710
710
  class ReuseBadgeAPITest(PytestOnlyAPITestCase):
711
711
  @pytest.fixture(autouse=True)
712
- def setup_func(self, api):
712
+ def setup_func(self):
713
713
  # Register at least two badges
714
714
  Reuse.__badges__["test-1"] = "Test 1"
715
715
  Reuse.__badges__["test-2"] = "Test 2"
716
716
 
717
717
  self.factory = badge_factory(Reuse)
718
- self.user = api.login(AdminFactory())
718
+ self.user = self.login(AdminFactory())
719
719
  self.reuse = ReuseFactory()
720
720
 
721
- def test_list(self, api):
722
- response = api.get(url_for("api.available_reuse_badges"))
721
+ def test_list(self):
722
+ response = self.get(url_for("api.available_reuse_badges"))
723
723
  assert200(response)
724
724
  assert len(response.json) == len(Reuse.__badges__)
725
725
  for kind, label in Reuse.__badges__.items():
726
726
  assert kind in response.json
727
727
  assert response.json[kind] == label
728
728
 
729
- def test_create(self, api):
729
+ def test_create(self):
730
730
  data = self.factory.as_dict()
731
- response = api.post(url_for("api.reuse_badges", reuse=self.reuse), data)
731
+ response = self.post(url_for("api.reuse_badges", reuse=self.reuse), data)
732
732
  assert201(response)
733
733
  self.reuse.reload()
734
734
  assert len(self.reuse.badges) == 1
735
735
 
736
- def test_create_same(self, api):
736
+ def test_create_same(self):
737
737
  data = self.factory.as_dict()
738
- api.post(url_for("api.reuse_badges", reuse=self.reuse), data)
739
- response = api.post(url_for("api.reuse_badges", reuse=self.reuse), data)
738
+ self.post(url_for("api.reuse_badges", reuse=self.reuse), data)
739
+ response = self.post(url_for("api.reuse_badges", reuse=self.reuse), data)
740
740
  assert200(response)
741
741
  self.reuse.reload()
742
742
  assert len(self.reuse.badges) == 1
743
743
 
744
- def test_create_2nd(self, api):
744
+ def test_create_2nd(self):
745
745
  # Explicitely setting the kind to avoid collisions given the
746
746
  # small number of choices for kinds.
747
747
  kinds_keys = list(Reuse.__badges__)
748
748
  self.reuse.add_badge(kinds_keys[0])
749
749
  data = self.factory.as_dict()
750
750
  data["kind"] = kinds_keys[1]
751
- response = api.post(url_for("api.reuse_badges", reuse=self.reuse), data)
751
+ response = self.post(url_for("api.reuse_badges", reuse=self.reuse), data)
752
752
  assert201(response)
753
753
  self.reuse.reload()
754
754
  assert len(self.reuse.badges) == 2
755
755
 
756
- def test_delete(self, api):
756
+ def test_delete(self):
757
757
  badge = self.factory()
758
758
  self.reuse.add_badge(badge.kind)
759
- response = api.delete(
759
+ response = self.delete(
760
760
  url_for("api.reuse_badge", reuse=self.reuse, badge_kind=str(badge.kind))
761
761
  )
762
762
  assert204(response)
763
763
  self.reuse.reload()
764
764
  assert len(self.reuse.badges) == 0
765
765
 
766
- def test_delete_404(self, api):
767
- response = api.delete(
766
+ def test_delete_404(self):
767
+ response = self.delete(
768
768
  url_for("api.reuse_badge", reuse=self.reuse, badge_kind=str(self.factory().kind))
769
769
  )
770
770
  assert404(response)
771
771
 
772
772
 
773
773
  class ReuseReferencesAPITest(PytestOnlyAPITestCase):
774
- def test_reuse_types_list(self, api):
774
+ def test_reuse_types_list(self):
775
775
  """It should fetch the reuse types list from the API"""
776
- response = api.get(url_for("api.reuse_types"))
776
+ response = self.get(url_for("api.reuse_types"))
777
777
  assert200(response)
778
778
  assert len(response.json) == len(REUSE_TYPES)
779
779
 
780
- def test_reuse_topics_list(self, api):
780
+ def test_reuse_topics_list(self):
781
781
  """It should fetch the reuse topics list from the API"""
782
- response = api.get(url_for("api.reuse_topics"))
782
+ response = self.get(url_for("api.reuse_topics"))
783
783
  assert200(response)
784
784
  assert len(response.json) == len(REUSE_TOPICS)