udata 14.0.0__py3-none-any.whl → 14.4.1.dev7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of udata might be problematic. Click here for more details.
- udata/api_fields.py +35 -4
- udata/app.py +18 -20
- udata/auth/__init__.py +29 -6
- udata/auth/forms.py +2 -2
- udata/auth/views.py +6 -3
- udata/commands/serve.py +3 -11
- udata/commands/tests/test_fixtures.py +9 -9
- udata/core/access_type/api.py +1 -1
- udata/core/access_type/constants.py +12 -8
- udata/core/activity/api.py +5 -6
- udata/core/badges/tests/test_commands.py +6 -6
- udata/core/csv.py +5 -0
- udata/core/dataservices/models.py +1 -1
- udata/core/dataservices/tasks.py +7 -0
- udata/core/dataset/api.py +2 -0
- udata/core/dataset/models.py +2 -2
- udata/core/dataset/permissions.py +31 -0
- udata/core/dataset/tasks.py +17 -5
- udata/core/discussions/models.py +1 -0
- udata/core/organization/api.py +8 -5
- udata/core/organization/mails.py +1 -1
- udata/core/organization/models.py +9 -1
- udata/core/organization/notifications.py +84 -0
- udata/core/organization/permissions.py +1 -1
- udata/core/organization/tasks.py +3 -0
- udata/core/pages/tests/test_api.py +32 -0
- udata/core/post/api.py +24 -69
- udata/core/post/models.py +84 -16
- udata/core/post/tests/test_api.py +24 -1
- udata/core/reports/api.py +18 -0
- udata/core/reports/models.py +42 -2
- udata/core/reuse/models.py +1 -1
- udata/core/reuse/tasks.py +7 -0
- udata/core/spatial/forms.py +2 -2
- udata/core/user/models.py +5 -1
- udata/features/notifications/api.py +7 -18
- udata/features/notifications/models.py +56 -0
- udata/features/notifications/tasks.py +25 -0
- udata/flask_mongoengine/engine.py +0 -4
- udata/frontend/markdown.py +2 -1
- udata/harvest/actions.py +21 -1
- udata/harvest/api.py +25 -8
- udata/harvest/backends/base.py +27 -1
- udata/harvest/backends/ckan/harvesters.py +11 -2
- udata/harvest/commands.py +33 -0
- udata/harvest/filters.py +17 -6
- udata/harvest/models.py +16 -0
- udata/harvest/permissions.py +27 -0
- udata/harvest/tests/ckan/test_ckan_backend.py +33 -0
- udata/harvest/tests/test_actions.py +58 -5
- udata/harvest/tests/test_api.py +276 -122
- udata/harvest/tests/test_base_backend.py +86 -1
- udata/harvest/tests/test_dcat_backend.py +57 -10
- udata/harvest/tests/test_filters.py +6 -0
- udata/i18n.py +1 -4
- udata/mail.py +5 -1
- udata/migrations/2025-10-31-create-membership-request-notifications.py +55 -0
- udata/migrations/2025-12-04-add-uuid-to-discussion-messages.py +28 -0
- udata/mongo/slug_fields.py +1 -1
- udata/rdf.py +45 -6
- udata/routing.py +2 -2
- udata/settings.py +7 -0
- udata/tasks.py +1 -0
- udata/templates/mail/message.html +5 -31
- udata/tests/__init__.py +27 -2
- udata/tests/api/__init__.py +108 -21
- udata/tests/api/test_activities_api.py +36 -0
- udata/tests/api/test_auth_api.py +121 -95
- udata/tests/api/test_base_api.py +7 -4
- udata/tests/api/test_datasets_api.py +44 -19
- udata/tests/api/test_organizations_api.py +192 -197
- udata/tests/api/test_reports_api.py +157 -0
- udata/tests/api/test_reuses_api.py +147 -147
- udata/tests/api/test_security_api.py +12 -12
- udata/tests/api/test_swagger.py +4 -4
- udata/tests/api/test_tags_api.py +8 -8
- udata/tests/api/test_user_api.py +1 -1
- udata/tests/apiv2/test_swagger.py +4 -4
- udata/tests/cli/test_cli_base.py +8 -9
- udata/tests/dataset/test_dataset_commands.py +4 -4
- udata/tests/dataset/test_dataset_model.py +66 -26
- udata/tests/dataset/test_dataset_rdf.py +99 -5
- udata/tests/frontend/test_auth.py +24 -1
- udata/tests/frontend/test_csv.py +0 -3
- udata/tests/helpers.py +25 -27
- udata/tests/organization/test_notifications.py +67 -2
- udata/tests/plugin.py +6 -261
- udata/tests/site/test_site_csv_exports.py +22 -10
- udata/tests/test_activity.py +9 -9
- udata/tests/test_dcat_commands.py +2 -2
- udata/tests/test_discussions.py +5 -5
- udata/tests/test_migrations.py +21 -21
- udata/tests/test_notifications.py +15 -57
- udata/tests/test_notifications_task.py +43 -0
- udata/tests/test_owned.py +81 -1
- udata/tests/test_storages.py +25 -19
- udata/tests/test_topics.py +77 -61
- udata/tests/test_uris.py +33 -0
- udata/tests/workers/test_jobs_commands.py +23 -23
- udata/translations/ar/LC_MESSAGES/udata.mo +0 -0
- udata/translations/ar/LC_MESSAGES/udata.po +187 -108
- udata/translations/de/LC_MESSAGES/udata.mo +0 -0
- udata/translations/de/LC_MESSAGES/udata.po +187 -108
- udata/translations/es/LC_MESSAGES/udata.mo +0 -0
- udata/translations/es/LC_MESSAGES/udata.po +187 -108
- udata/translations/fr/LC_MESSAGES/udata.mo +0 -0
- udata/translations/fr/LC_MESSAGES/udata.po +188 -109
- udata/translations/it/LC_MESSAGES/udata.mo +0 -0
- udata/translations/it/LC_MESSAGES/udata.po +187 -108
- udata/translations/pt/LC_MESSAGES/udata.mo +0 -0
- udata/translations/pt/LC_MESSAGES/udata.po +187 -108
- udata/translations/sr/LC_MESSAGES/udata.mo +0 -0
- udata/translations/sr/LC_MESSAGES/udata.po +187 -108
- udata/translations/udata.pot +215 -106
- udata/uris.py +0 -2
- udata-14.4.1.dev7.dist-info/METADATA +109 -0
- {udata-14.0.0.dist-info → udata-14.4.1.dev7.dist-info}/RECORD +121 -123
- udata/core/post/forms.py +0 -30
- udata/flask_mongoengine/json.py +0 -38
- udata/templates/mail/base.html +0 -105
- udata/templates/mail/base.txt +0 -6
- udata/templates/mail/button.html +0 -3
- udata/templates/mail/layouts/1-column.html +0 -19
- udata/templates/mail/layouts/2-columns.html +0 -20
- udata/templates/mail/layouts/center-panel.html +0 -16
- udata-14.0.0.dist-info/METADATA +0 -132
- {udata-14.0.0.dist-info → udata-14.4.1.dev7.dist-info}/WHEEL +0 -0
- {udata-14.0.0.dist-info → udata-14.4.1.dev7.dist-info}/entry_points.txt +0 -0
- {udata-14.0.0.dist-info → udata-14.4.1.dev7.dist-info}/licenses/LICENSE +0 -0
- {udata-14.0.0.dist-info → udata-14.4.1.dev7.dist-info}/top_level.txt +0 -0
|
@@ -34,85 +34,85 @@ from udata.utils import faker
|
|
|
34
34
|
|
|
35
35
|
|
|
36
36
|
class OrganizationAPITest(PytestOnlyAPITestCase):
|
|
37
|
-
def test_organization_api_list(self
|
|
37
|
+
def test_organization_api_list(self):
|
|
38
38
|
"""It should fetch an organization list from the API"""
|
|
39
39
|
organizations = OrganizationFactory.create_batch(3)
|
|
40
40
|
|
|
41
|
-
response =
|
|
41
|
+
response = self.get(url_for("api.organizations"))
|
|
42
42
|
assert200(response)
|
|
43
43
|
len(response.json["data"]) == len(organizations)
|
|
44
44
|
|
|
45
|
-
def test_organization_api_list_with_filters(self
|
|
45
|
+
def test_organization_api_list_with_filters(self):
|
|
46
46
|
"""It should filter the organization list"""
|
|
47
47
|
org = OrganizationFactory(business_number_id="13002526500013")
|
|
48
48
|
org_public_service = OrganizationFactory()
|
|
49
49
|
org_public_service.add_badge(org_constants.PUBLIC_SERVICE)
|
|
50
50
|
|
|
51
51
|
#### Badges ####
|
|
52
|
-
response =
|
|
52
|
+
response = self.get(url_for("api.organizations", badge=org_constants.PUBLIC_SERVICE))
|
|
53
53
|
assert200(response)
|
|
54
54
|
assert len(response.json["data"]) == 1
|
|
55
55
|
assert response.json["data"][0]["id"] == str(org_public_service.id)
|
|
56
56
|
|
|
57
|
-
response =
|
|
57
|
+
response = self.get(url_for("api.organizations", badge="bad-badge"))
|
|
58
58
|
assert400(response)
|
|
59
59
|
|
|
60
60
|
#### Name ####
|
|
61
|
-
response =
|
|
61
|
+
response = self.get(url_for("api.organizations", name=org.name))
|
|
62
62
|
assert200(response)
|
|
63
63
|
assert len(response.json["data"]) == 1
|
|
64
64
|
assert response.json["data"][0]["id"] == str(org.id)
|
|
65
65
|
|
|
66
|
-
response =
|
|
66
|
+
response = self.get(url_for("api.organizations", name=org.name.upper()))
|
|
67
67
|
assert200(response)
|
|
68
68
|
assert len(response.json["data"]) == 1
|
|
69
69
|
assert response.json["data"][0]["id"] == str(org.id)
|
|
70
70
|
|
|
71
|
-
response =
|
|
71
|
+
response = self.get(url_for("api.organizations", name="Some other name"))
|
|
72
72
|
assert200(response)
|
|
73
73
|
assert len(response.json["data"]) == 0
|
|
74
74
|
|
|
75
75
|
#### SIRET ####
|
|
76
|
-
response =
|
|
76
|
+
response = self.get(url_for("api.organizations", business_number_id=org.business_number_id))
|
|
77
77
|
assert200(response)
|
|
78
78
|
print(response.json["data"])
|
|
79
79
|
assert len(response.json["data"]) == 1
|
|
80
80
|
assert response.json["data"][0]["id"] == str(org.id)
|
|
81
81
|
|
|
82
|
-
response =
|
|
82
|
+
response = self.get(url_for("api.organizations", business_number_id="xxx"))
|
|
83
83
|
assert200(response)
|
|
84
84
|
assert len(response.json["data"]) == 0
|
|
85
85
|
|
|
86
|
-
def test_organization_role_api_get(self
|
|
86
|
+
def test_organization_role_api_get(self):
|
|
87
87
|
"""It should fetch an organization's roles list from the API"""
|
|
88
|
-
response =
|
|
88
|
+
response = self.get(url_for("api.org_roles"))
|
|
89
89
|
assert200(response)
|
|
90
90
|
|
|
91
|
-
def test_organization_api_get(self
|
|
91
|
+
def test_organization_api_get(self):
|
|
92
92
|
"""It should fetch an organization from the API"""
|
|
93
93
|
organization = OrganizationFactory()
|
|
94
|
-
response =
|
|
94
|
+
response = self.get(url_for("api.organization", org=organization))
|
|
95
95
|
assert200(response)
|
|
96
96
|
|
|
97
|
-
def test_organization_api_get_deleted(self
|
|
97
|
+
def test_organization_api_get_deleted(self):
|
|
98
98
|
"""It should not fetch a deleted organization from the API"""
|
|
99
99
|
organization = OrganizationFactory(deleted=datetime.utcnow())
|
|
100
|
-
response =
|
|
100
|
+
response = self.get(url_for("api.organization", org=organization))
|
|
101
101
|
assert410(response)
|
|
102
102
|
|
|
103
|
-
def test_organization_api_get_deleted_but_authorized(self
|
|
103
|
+
def test_organization_api_get_deleted_but_authorized(self):
|
|
104
104
|
"""It should fetch a deleted organization from the API if authorized"""
|
|
105
|
-
user =
|
|
105
|
+
user = self.login()
|
|
106
106
|
member = Member(user=user, role="editor")
|
|
107
107
|
organization = OrganizationFactory(deleted=datetime.utcnow(), members=[member])
|
|
108
|
-
response =
|
|
108
|
+
response = self.get(url_for("api.organization", org=organization))
|
|
109
109
|
assert200(response)
|
|
110
110
|
|
|
111
|
-
def test_organization_api_create(self
|
|
111
|
+
def test_organization_api_create(self):
|
|
112
112
|
"""It should create an organization from the API"""
|
|
113
113
|
data = OrganizationFactory.as_dict()
|
|
114
|
-
user =
|
|
115
|
-
response =
|
|
114
|
+
user = self.login()
|
|
115
|
+
response = self.post(url_for("api.organizations"), data)
|
|
116
116
|
assert201(response)
|
|
117
117
|
assert Organization.objects.count() == 1
|
|
118
118
|
|
|
@@ -122,121 +122,121 @@ class OrganizationAPITest(PytestOnlyAPITestCase):
|
|
|
122
122
|
assert member.role == "admin", "Current user should be an administrator"
|
|
123
123
|
assert org.get_metrics()["members"] == 1
|
|
124
124
|
|
|
125
|
-
def test_organization_api_update(self
|
|
125
|
+
def test_organization_api_update(self):
|
|
126
126
|
"""It should update an organization from the API"""
|
|
127
|
-
user =
|
|
127
|
+
user = self.login()
|
|
128
128
|
member = Member(user=user, role="admin")
|
|
129
129
|
org = OrganizationFactory(members=[member])
|
|
130
130
|
data = org.to_dict()
|
|
131
131
|
data["description"] = "new description"
|
|
132
|
-
response =
|
|
132
|
+
response = self.put(url_for("api.organization", org=org), data)
|
|
133
133
|
assert200(response)
|
|
134
134
|
assert Organization.objects.count() == 1
|
|
135
135
|
assert Organization.objects.first().description == "new description"
|
|
136
136
|
|
|
137
|
-
def test_organization_api_update_business_number_id(self
|
|
137
|
+
def test_organization_api_update_business_number_id(self):
|
|
138
138
|
"""It should update an organization from the API by adding a business number id"""
|
|
139
|
-
user =
|
|
139
|
+
user = self.login()
|
|
140
140
|
member = Member(user=user, role="admin")
|
|
141
141
|
org = OrganizationFactory(members=[member])
|
|
142
142
|
data = org.to_dict()
|
|
143
143
|
data["business_number_id"] = "13002526500013"
|
|
144
|
-
response =
|
|
144
|
+
response = self.put(url_for("api.organization", org=org), data)
|
|
145
145
|
assert200(response)
|
|
146
146
|
assert Organization.objects.count() == 1
|
|
147
147
|
assert Organization.objects.first().business_number_id == "13002526500013"
|
|
148
148
|
|
|
149
|
-
def test_organization_api_update_business_number_id_failing(self
|
|
149
|
+
def test_organization_api_update_business_number_id_failing(self):
|
|
150
150
|
"""It should update an organization from the API by adding a business number id"""
|
|
151
|
-
user =
|
|
151
|
+
user = self.login()
|
|
152
152
|
member = Member(user=user, role="admin")
|
|
153
153
|
org = OrganizationFactory(members=[member])
|
|
154
154
|
data = org.to_dict()
|
|
155
155
|
data["business_number_id"] = "110014016"
|
|
156
|
-
response =
|
|
156
|
+
response = self.put(url_for("api.organization", org=org), data)
|
|
157
157
|
assert400(response)
|
|
158
158
|
assert response.json["errors"]["business_number_id"][0] == _(
|
|
159
159
|
"A siret number is made of 14 digits"
|
|
160
160
|
)
|
|
161
161
|
|
|
162
162
|
data["business_number_id"] = "12345678901234"
|
|
163
|
-
response =
|
|
163
|
+
response = self.put(url_for("api.organization", org=org), data)
|
|
164
164
|
assert400(response)
|
|
165
165
|
assert response.json["errors"]["business_number_id"][0] == _("Invalid Siret number")
|
|
166
166
|
|
|
167
167
|
data["business_number_id"] = "tttttttttttttt"
|
|
168
|
-
response =
|
|
168
|
+
response = self.put(url_for("api.organization", org=org), data)
|
|
169
169
|
assert400(response)
|
|
170
170
|
assert response.json["errors"]["business_number_id"][0] == _(
|
|
171
171
|
"A siret number is only made of digits"
|
|
172
172
|
)
|
|
173
173
|
|
|
174
|
-
def test_organization_api_update_deleted(self
|
|
174
|
+
def test_organization_api_update_deleted(self):
|
|
175
175
|
"""It should not update a deleted organization from the API"""
|
|
176
176
|
org = OrganizationFactory(deleted=datetime.utcnow())
|
|
177
177
|
data = org.to_dict()
|
|
178
178
|
data["description"] = "new description"
|
|
179
|
-
|
|
180
|
-
response =
|
|
179
|
+
self.login()
|
|
180
|
+
response = self.put(url_for("api.organization", org=org), data)
|
|
181
181
|
assert410(response)
|
|
182
182
|
assert Organization.objects.first().description == org.description
|
|
183
183
|
|
|
184
|
-
def test_organization_api_update_forbidden(self
|
|
184
|
+
def test_organization_api_update_forbidden(self):
|
|
185
185
|
"""It should not update an organization from the API if not admin"""
|
|
186
186
|
org = OrganizationFactory()
|
|
187
187
|
data = org.to_dict()
|
|
188
188
|
data["description"] = "new description"
|
|
189
|
-
|
|
190
|
-
response =
|
|
189
|
+
self.login()
|
|
190
|
+
response = self.put(url_for("api.organization", org=org), data)
|
|
191
191
|
assert403(response)
|
|
192
192
|
assert Organization.objects.count() == 1
|
|
193
193
|
assert Organization.objects.first().description == org.description
|
|
194
194
|
|
|
195
|
-
def test_organization_api_delete(self
|
|
195
|
+
def test_organization_api_delete(self):
|
|
196
196
|
"""It should delete an organization from the API"""
|
|
197
|
-
user =
|
|
197
|
+
user = self.login()
|
|
198
198
|
member = Member(user=user, role="admin")
|
|
199
199
|
org = OrganizationFactory(members=[member])
|
|
200
|
-
response =
|
|
200
|
+
response = self.delete(url_for("api.organization", org=org))
|
|
201
201
|
assert204(response)
|
|
202
202
|
assert Organization.objects.count() == 1
|
|
203
203
|
assert Organization.objects[0].deleted is not None
|
|
204
204
|
|
|
205
|
-
def test_organization_api_delete_deleted(self
|
|
205
|
+
def test_organization_api_delete_deleted(self):
|
|
206
206
|
"""It should not delete a deleted organization from the API"""
|
|
207
|
-
|
|
207
|
+
self.login()
|
|
208
208
|
organization = OrganizationFactory(deleted=datetime.utcnow())
|
|
209
|
-
response =
|
|
209
|
+
response = self.delete(url_for("api.organization", org=organization))
|
|
210
210
|
assert410(response)
|
|
211
211
|
assert Organization.objects[0].deleted is not None
|
|
212
212
|
|
|
213
|
-
def test_organization_api_delete_as_editor_forbidden(self
|
|
213
|
+
def test_organization_api_delete_as_editor_forbidden(self):
|
|
214
214
|
"""It should not delete an organization from the API if not admin"""
|
|
215
|
-
user =
|
|
215
|
+
user = self.login()
|
|
216
216
|
member = Member(user=user, role="editor")
|
|
217
217
|
org = OrganizationFactory(members=[member])
|
|
218
|
-
response =
|
|
218
|
+
response = self.delete(url_for("api.organization", org=org))
|
|
219
219
|
assert403(response)
|
|
220
220
|
assert Organization.objects.count() == 1
|
|
221
221
|
assert Organization.objects[0].deleted is None
|
|
222
222
|
|
|
223
|
-
def test_organization_api_delete_as_non_member_forbidden(self
|
|
223
|
+
def test_organization_api_delete_as_non_member_forbidden(self):
|
|
224
224
|
"""It should delete an organization from the API if not member"""
|
|
225
|
-
|
|
225
|
+
self.login()
|
|
226
226
|
org = OrganizationFactory()
|
|
227
|
-
response =
|
|
227
|
+
response = self.delete(url_for("api.organization", org=org))
|
|
228
228
|
assert403(response)
|
|
229
229
|
assert Organization.objects.count() == 1
|
|
230
230
|
assert Organization.objects[0].deleted is None
|
|
231
231
|
|
|
232
232
|
|
|
233
233
|
class MembershipAPITest(PytestOnlyAPITestCase):
|
|
234
|
-
def test_request_membership(self
|
|
234
|
+
def test_request_membership(self):
|
|
235
235
|
organization = OrganizationFactory()
|
|
236
|
-
user =
|
|
236
|
+
user = self.login()
|
|
237
237
|
data = {"comment": "a comment"}
|
|
238
238
|
|
|
239
|
-
response =
|
|
239
|
+
response = self.post(url_for("api.request_membership", org=organization), data)
|
|
240
240
|
assert201(response)
|
|
241
241
|
|
|
242
242
|
organization.reload()
|
|
@@ -253,13 +253,13 @@ class MembershipAPITest(PytestOnlyAPITestCase):
|
|
|
253
253
|
assert request.handled_by is None
|
|
254
254
|
assert request.refusal_comment is None
|
|
255
255
|
|
|
256
|
-
def test_request_existing_pending_membership_do_not_duplicate_it(self
|
|
257
|
-
user =
|
|
256
|
+
def test_request_existing_pending_membership_do_not_duplicate_it(self):
|
|
257
|
+
user = self.login()
|
|
258
258
|
previous_request = MembershipRequest(user=user, comment="previous")
|
|
259
259
|
organization = OrganizationFactory(requests=[previous_request])
|
|
260
260
|
data = {"comment": "a comment"}
|
|
261
261
|
|
|
262
|
-
response =
|
|
262
|
+
response = self.post(url_for("api.request_membership", org=organization), data)
|
|
263
263
|
assert200(response)
|
|
264
264
|
|
|
265
265
|
organization.reload()
|
|
@@ -276,14 +276,14 @@ class MembershipAPITest(PytestOnlyAPITestCase):
|
|
|
276
276
|
assert request.handled_by is None
|
|
277
277
|
assert request.refusal_comment is None
|
|
278
278
|
|
|
279
|
-
def test_get_membership_requests(self
|
|
280
|
-
user =
|
|
279
|
+
def test_get_membership_requests(self):
|
|
280
|
+
user = self.login()
|
|
281
281
|
applicant = UserFactory(email="thibaud@example.org")
|
|
282
282
|
membership_request = MembershipRequest(user=applicant, comment="test")
|
|
283
283
|
member = Member(user=user, role="admin")
|
|
284
284
|
organization = OrganizationFactory(members=[member], requests=[membership_request])
|
|
285
285
|
|
|
286
|
-
response =
|
|
286
|
+
response = self.get(url_for("api.request_membership", org=organization))
|
|
287
287
|
assert200(response)
|
|
288
288
|
|
|
289
289
|
assert len(response.json) == 1
|
|
@@ -292,21 +292,21 @@ class MembershipAPITest(PytestOnlyAPITestCase):
|
|
|
292
292
|
response.json[0]["user"]["email"] == "th*****@example.org"
|
|
293
293
|
) # Can see partially obfuscated email of applicant
|
|
294
294
|
|
|
295
|
-
def test_only_org_member_can_get_membership_requests(self
|
|
296
|
-
|
|
295
|
+
def test_only_org_member_can_get_membership_requests(self):
|
|
296
|
+
self.login()
|
|
297
297
|
applicant = UserFactory(email="thibaud@example.org")
|
|
298
298
|
membership_request = MembershipRequest(user=applicant, comment="test")
|
|
299
299
|
organization = OrganizationFactory(members=[], requests=[membership_request])
|
|
300
300
|
|
|
301
|
-
response =
|
|
301
|
+
response = self.get(url_for("api.request_membership", org=organization))
|
|
302
302
|
assert403(response)
|
|
303
303
|
|
|
304
|
-
def test_applicant_can_get_their_membership_requests(self
|
|
305
|
-
applicant =
|
|
304
|
+
def test_applicant_can_get_their_membership_requests(self):
|
|
305
|
+
applicant = self.login()
|
|
306
306
|
membership_request = MembershipRequest(user=applicant, comment="test")
|
|
307
307
|
organization = OrganizationFactory(members=[], requests=[membership_request])
|
|
308
308
|
|
|
309
|
-
response =
|
|
309
|
+
response = self.get(
|
|
310
310
|
url_for("api.request_membership", org=organization),
|
|
311
311
|
query_string={"user": str(applicant.id)},
|
|
312
312
|
)
|
|
@@ -320,13 +320,11 @@ class MembershipAPITest(PytestOnlyAPITestCase):
|
|
|
320
320
|
"refused",
|
|
321
321
|
],
|
|
322
322
|
)
|
|
323
|
-
def test_applicant_can_get_their_membership_requests_with_status(
|
|
324
|
-
|
|
325
|
-
):
|
|
326
|
-
applicant = api.login()
|
|
323
|
+
def test_applicant_can_get_their_membership_requests_with_status(self, searched_status: str):
|
|
324
|
+
applicant = self.login()
|
|
327
325
|
membership_request = MembershipRequest(user=applicant, comment="test")
|
|
328
326
|
organization = OrganizationFactory(members=[], requests=[membership_request])
|
|
329
|
-
response =
|
|
327
|
+
response = self.get(
|
|
330
328
|
url_for("api.request_membership", org=organization),
|
|
331
329
|
query_string={"user": str(applicant.id), "status": searched_status},
|
|
332
330
|
)
|
|
@@ -337,7 +335,7 @@ class MembershipAPITest(PytestOnlyAPITestCase):
|
|
|
337
335
|
else:
|
|
338
336
|
assert len(requests) == 0
|
|
339
337
|
|
|
340
|
-
def test_get_members_with_or_without_email(self
|
|
338
|
+
def test_get_members_with_or_without_email(self):
|
|
341
339
|
admin = Member(
|
|
342
340
|
user=UserFactory(email="admin@example.org"), role="admin", since="2024-04-14"
|
|
343
341
|
)
|
|
@@ -347,8 +345,8 @@ class MembershipAPITest(PytestOnlyAPITestCase):
|
|
|
347
345
|
organization = OrganizationFactory(members=[admin, editor])
|
|
348
346
|
|
|
349
347
|
# Organization admin can partially see emails
|
|
350
|
-
|
|
351
|
-
response =
|
|
348
|
+
self.login(admin.user)
|
|
349
|
+
response = self.get(url_for("api.organization", org=organization))
|
|
352
350
|
assert200(response)
|
|
353
351
|
|
|
354
352
|
members = response.json["members"]
|
|
@@ -361,8 +359,8 @@ class MembershipAPITest(PytestOnlyAPITestCase):
|
|
|
361
359
|
assert members[1]["user"]["email"] == "ed****@example.org"
|
|
362
360
|
|
|
363
361
|
# Organization editor can partially see emails
|
|
364
|
-
|
|
365
|
-
response =
|
|
362
|
+
self.login(editor.user)
|
|
363
|
+
response = self.get(url_for("api.organization", org=organization))
|
|
366
364
|
assert200(response)
|
|
367
365
|
|
|
368
366
|
members = response.json["members"]
|
|
@@ -375,8 +373,8 @@ class MembershipAPITest(PytestOnlyAPITestCase):
|
|
|
375
373
|
assert members[1]["user"]["email"] == "ed****@example.org"
|
|
376
374
|
|
|
377
375
|
# Others cannot see emails
|
|
378
|
-
|
|
379
|
-
response =
|
|
376
|
+
self.login(other)
|
|
377
|
+
response = self.get(url_for("api.organization", org=organization))
|
|
380
378
|
assert200(response)
|
|
381
379
|
|
|
382
380
|
members = response.json["members"]
|
|
@@ -389,8 +387,8 @@ class MembershipAPITest(PytestOnlyAPITestCase):
|
|
|
389
387
|
assert members[1]["user"]["email"] == "***@example.org"
|
|
390
388
|
|
|
391
389
|
# Super admin of udata can see emails
|
|
392
|
-
|
|
393
|
-
response =
|
|
390
|
+
self.login(AdminFactory())
|
|
391
|
+
response = self.get(url_for("api.organization", org=organization))
|
|
394
392
|
assert200(response)
|
|
395
393
|
|
|
396
394
|
members = response.json["members"]
|
|
@@ -402,15 +400,15 @@ class MembershipAPITest(PytestOnlyAPITestCase):
|
|
|
402
400
|
assert members[1]["role"] == "editor"
|
|
403
401
|
assert members[1]["user"]["email"] == "editor@example.org"
|
|
404
402
|
|
|
405
|
-
def test_accept_membership(self
|
|
406
|
-
user =
|
|
403
|
+
def test_accept_membership(self):
|
|
404
|
+
user = self.login()
|
|
407
405
|
applicant = UserFactory()
|
|
408
406
|
membership_request = MembershipRequest(user=applicant, comment="test")
|
|
409
407
|
member = Member(user=user, role="admin")
|
|
410
408
|
organization = OrganizationFactory(members=[member], requests=[membership_request])
|
|
411
409
|
|
|
412
410
|
api_url = url_for("api.accept_membership", org=organization, id=membership_request.id)
|
|
413
|
-
response =
|
|
411
|
+
response = self.post(api_url)
|
|
414
412
|
assert200(response)
|
|
415
413
|
|
|
416
414
|
assert response.json["role"] == "editor"
|
|
@@ -432,33 +430,33 @@ class MembershipAPITest(PytestOnlyAPITestCase):
|
|
|
432
430
|
|
|
433
431
|
# test accepting twice will raise 409
|
|
434
432
|
api_url = url_for("api.accept_membership", org=organization, id=membership_request.id)
|
|
435
|
-
response =
|
|
433
|
+
response = self.post(api_url)
|
|
436
434
|
assert_status(response, 409)
|
|
437
435
|
|
|
438
|
-
def test_only_admin_can_accept_membership(self
|
|
439
|
-
user =
|
|
436
|
+
def test_only_admin_can_accept_membership(self):
|
|
437
|
+
user = self.login()
|
|
440
438
|
applicant = UserFactory()
|
|
441
439
|
membership_request = MembershipRequest(user=applicant, comment="test")
|
|
442
440
|
member = Member(user=user, role="editor")
|
|
443
441
|
organization = OrganizationFactory(members=[member], requests=[membership_request])
|
|
444
442
|
|
|
445
443
|
api_url = url_for("api.accept_membership", org=organization, id=membership_request.id)
|
|
446
|
-
response =
|
|
444
|
+
response = self.post(api_url)
|
|
447
445
|
assert403(response)
|
|
448
446
|
|
|
449
|
-
def test_accept_membership_404(self
|
|
450
|
-
user =
|
|
447
|
+
def test_accept_membership_404(self):
|
|
448
|
+
user = self.login()
|
|
451
449
|
member = Member(user=user, role="admin")
|
|
452
450
|
organization = OrganizationFactory(members=[member])
|
|
453
451
|
|
|
454
452
|
api_url = url_for("api.accept_membership", org=organization, id=MembershipRequest().id)
|
|
455
|
-
response =
|
|
453
|
+
response = self.post(api_url)
|
|
456
454
|
assert404(response)
|
|
457
455
|
|
|
458
456
|
assert response.json["message"] == "Unknown membership request id"
|
|
459
457
|
|
|
460
|
-
def test_refuse_membership(self
|
|
461
|
-
user =
|
|
458
|
+
def test_refuse_membership(self):
|
|
459
|
+
user = self.login()
|
|
462
460
|
applicant = UserFactory()
|
|
463
461
|
membership_request = MembershipRequest(user=applicant, comment="test")
|
|
464
462
|
member = Member(user=user, role="admin")
|
|
@@ -466,7 +464,7 @@ class MembershipAPITest(PytestOnlyAPITestCase):
|
|
|
466
464
|
data = {"comment": "no"}
|
|
467
465
|
|
|
468
466
|
api_url = url_for("api.refuse_membership", org=organization, id=membership_request.id)
|
|
469
|
-
response =
|
|
467
|
+
response = self.post(api_url, data)
|
|
470
468
|
assert200(response)
|
|
471
469
|
|
|
472
470
|
organization.reload()
|
|
@@ -484,8 +482,8 @@ class MembershipAPITest(PytestOnlyAPITestCase):
|
|
|
484
482
|
assert request.handled_by == user
|
|
485
483
|
assert request.handled_on is not None
|
|
486
484
|
|
|
487
|
-
def test_only_admin_can_refuse_membership(self
|
|
488
|
-
user =
|
|
485
|
+
def test_only_admin_can_refuse_membership(self):
|
|
486
|
+
user = self.login()
|
|
489
487
|
applicant = UserFactory()
|
|
490
488
|
membership_request = MembershipRequest(user=applicant, comment="test")
|
|
491
489
|
member = Member(user=user, role="editor")
|
|
@@ -493,22 +491,22 @@ class MembershipAPITest(PytestOnlyAPITestCase):
|
|
|
493
491
|
data = {"comment": "no"}
|
|
494
492
|
|
|
495
493
|
api_url = url_for("api.refuse_membership", org=organization, id=membership_request.id)
|
|
496
|
-
response =
|
|
494
|
+
response = self.post(api_url, data)
|
|
497
495
|
assert403(response)
|
|
498
496
|
|
|
499
|
-
def test_refuse_membership_404(self
|
|
500
|
-
user =
|
|
497
|
+
def test_refuse_membership_404(self):
|
|
498
|
+
user = self.login()
|
|
501
499
|
member = Member(user=user, role="admin")
|
|
502
500
|
organization = OrganizationFactory(members=[member])
|
|
503
501
|
|
|
504
502
|
api_url = url_for("api.refuse_membership", org=organization, id=MembershipRequest().id)
|
|
505
|
-
response =
|
|
503
|
+
response = self.post(api_url)
|
|
506
504
|
assert404(response)
|
|
507
505
|
|
|
508
506
|
assert response.json["message"] == "Unknown membership request id"
|
|
509
507
|
|
|
510
|
-
def test_create_member(self
|
|
511
|
-
user =
|
|
508
|
+
def test_create_member(self):
|
|
509
|
+
user = self.login()
|
|
512
510
|
added_user = UserFactory()
|
|
513
511
|
organization = OrganizationFactory(
|
|
514
512
|
members=[
|
|
@@ -517,7 +515,7 @@ class MembershipAPITest(PytestOnlyAPITestCase):
|
|
|
517
515
|
)
|
|
518
516
|
|
|
519
517
|
api_url = url_for("api.member", org=organization, user=added_user)
|
|
520
|
-
response =
|
|
518
|
+
response = self.post(api_url, {"role": "admin"})
|
|
521
519
|
|
|
522
520
|
assert201(response)
|
|
523
521
|
|
|
@@ -528,8 +526,8 @@ class MembershipAPITest(PytestOnlyAPITestCase):
|
|
|
528
526
|
assert organization.is_admin(added_user)
|
|
529
527
|
assert organization.get_metrics()["members"] == 2
|
|
530
528
|
|
|
531
|
-
def test_only_admin_can_create_member(self
|
|
532
|
-
user =
|
|
529
|
+
def test_only_admin_can_create_member(self):
|
|
530
|
+
user = self.login()
|
|
533
531
|
added_user = UserFactory()
|
|
534
532
|
organization = OrganizationFactory(
|
|
535
533
|
members=[
|
|
@@ -538,22 +536,22 @@ class MembershipAPITest(PytestOnlyAPITestCase):
|
|
|
538
536
|
)
|
|
539
537
|
|
|
540
538
|
api_url = url_for("api.member", org=organization, user=added_user)
|
|
541
|
-
response =
|
|
539
|
+
response = self.post(api_url, {"role": "editor"})
|
|
542
540
|
|
|
543
541
|
assert403(response)
|
|
544
542
|
|
|
545
543
|
organization.reload()
|
|
546
544
|
assert not organization.is_member(added_user)
|
|
547
545
|
|
|
548
|
-
def test_create_member_exists(self
|
|
549
|
-
user =
|
|
546
|
+
def test_create_member_exists(self):
|
|
547
|
+
user = self.login()
|
|
550
548
|
added_user = UserFactory()
|
|
551
549
|
organization = OrganizationFactory(
|
|
552
550
|
members=[Member(user=user, role="admin"), Member(user=added_user, role="editor")]
|
|
553
551
|
)
|
|
554
552
|
|
|
555
553
|
api_url = url_for("api.member", org=organization, user=added_user)
|
|
556
|
-
response =
|
|
554
|
+
response = self.post(api_url, {"role": "admin"})
|
|
557
555
|
|
|
558
556
|
assert_status(response, 409)
|
|
559
557
|
|
|
@@ -563,15 +561,15 @@ class MembershipAPITest(PytestOnlyAPITestCase):
|
|
|
563
561
|
assert organization.is_member(added_user)
|
|
564
562
|
assert not organization.is_admin(added_user)
|
|
565
563
|
|
|
566
|
-
def test_update_member(self
|
|
567
|
-
user =
|
|
564
|
+
def test_update_member(self):
|
|
565
|
+
user = self.login()
|
|
568
566
|
updated_user = UserFactory()
|
|
569
567
|
organization = OrganizationFactory(
|
|
570
568
|
members=[Member(user=user, role="admin"), Member(user=updated_user, role="editor")]
|
|
571
569
|
)
|
|
572
570
|
|
|
573
571
|
api_url = url_for("api.member", org=organization, user=updated_user)
|
|
574
|
-
response =
|
|
572
|
+
response = self.put(api_url, {"role": "admin"})
|
|
575
573
|
|
|
576
574
|
assert200(response)
|
|
577
575
|
|
|
@@ -581,15 +579,15 @@ class MembershipAPITest(PytestOnlyAPITestCase):
|
|
|
581
579
|
assert organization.is_member(updated_user)
|
|
582
580
|
assert organization.is_admin(updated_user)
|
|
583
581
|
|
|
584
|
-
def test_only_admin_can_update_member(self
|
|
585
|
-
user =
|
|
582
|
+
def test_only_admin_can_update_member(self):
|
|
583
|
+
user = self.login()
|
|
586
584
|
updated_user = UserFactory()
|
|
587
585
|
organization = OrganizationFactory(
|
|
588
586
|
members=[Member(user=user, role="editor"), Member(user=updated_user, role="editor")]
|
|
589
587
|
)
|
|
590
588
|
|
|
591
589
|
api_url = url_for("api.member", org=organization, user=updated_user)
|
|
592
|
-
response =
|
|
590
|
+
response = self.put(api_url, {"role": "admin"})
|
|
593
591
|
|
|
594
592
|
assert403(response)
|
|
595
593
|
|
|
@@ -597,42 +595,42 @@ class MembershipAPITest(PytestOnlyAPITestCase):
|
|
|
597
595
|
assert organization.is_member(updated_user)
|
|
598
596
|
assert not organization.is_admin(updated_user)
|
|
599
597
|
|
|
600
|
-
def test_delete_member(self
|
|
601
|
-
user =
|
|
598
|
+
def test_delete_member(self):
|
|
599
|
+
user = self.login()
|
|
602
600
|
deleted_user = UserFactory()
|
|
603
601
|
organization = OrganizationFactory(
|
|
604
602
|
members=[Member(user=user, role="admin"), Member(user=deleted_user, role="editor")]
|
|
605
603
|
)
|
|
606
604
|
|
|
607
605
|
api_url = url_for("api.member", org=organization, user=deleted_user)
|
|
608
|
-
response =
|
|
606
|
+
response = self.delete(api_url)
|
|
609
607
|
assert204(response)
|
|
610
608
|
|
|
611
609
|
organization.reload()
|
|
612
610
|
assert not organization.is_member(deleted_user)
|
|
613
611
|
assert organization.get_metrics()["members"] == 1
|
|
614
612
|
|
|
615
|
-
def test_only_admin_can_delete_member(self
|
|
616
|
-
user =
|
|
613
|
+
def test_only_admin_can_delete_member(self):
|
|
614
|
+
user = self.login()
|
|
617
615
|
deleted_user = UserFactory()
|
|
618
616
|
organization = OrganizationFactory(
|
|
619
617
|
members=[Member(user=user, role="editor"), Member(user=deleted_user, role="editor")]
|
|
620
618
|
)
|
|
621
619
|
|
|
622
620
|
api_url = url_for("api.member", org=organization, user=deleted_user)
|
|
623
|
-
response =
|
|
621
|
+
response = self.delete(api_url)
|
|
624
622
|
assert403(response)
|
|
625
623
|
|
|
626
624
|
organization.reload()
|
|
627
625
|
assert organization.is_member(deleted_user)
|
|
628
626
|
|
|
629
|
-
def test_follow_org(self
|
|
627
|
+
def test_follow_org(self):
|
|
630
628
|
"""It should follow an organization on POST"""
|
|
631
|
-
user =
|
|
629
|
+
user = self.login()
|
|
632
630
|
to_follow = OrganizationFactory()
|
|
633
631
|
|
|
634
632
|
url = url_for("api.organization_followers", id=to_follow.id)
|
|
635
|
-
response =
|
|
633
|
+
response = self.post(url)
|
|
636
634
|
assert201(response)
|
|
637
635
|
|
|
638
636
|
to_follow.count_followers()
|
|
@@ -645,14 +643,14 @@ class MembershipAPITest(PytestOnlyAPITestCase):
|
|
|
645
643
|
assert Follow.objects.following(user).count() == 1
|
|
646
644
|
assert Follow.objects.followers(user).count() == 0
|
|
647
645
|
|
|
648
|
-
def test_unfollow_org(self
|
|
646
|
+
def test_unfollow_org(self):
|
|
649
647
|
"""It should unfollow the organization on DELETE"""
|
|
650
|
-
user =
|
|
648
|
+
user = self.login()
|
|
651
649
|
to_follow = OrganizationFactory()
|
|
652
650
|
Follow.objects.create(follower=user, following=to_follow)
|
|
653
651
|
|
|
654
652
|
url = url_for("api.organization_followers", id=to_follow.id)
|
|
655
|
-
response =
|
|
653
|
+
response = self.delete(url)
|
|
656
654
|
assert200(response)
|
|
657
655
|
|
|
658
656
|
nb_followers = Follow.objects.followers(to_follow).count()
|
|
@@ -664,14 +662,14 @@ class MembershipAPITest(PytestOnlyAPITestCase):
|
|
|
664
662
|
assert Follow.objects.following(user).count() == 0
|
|
665
663
|
assert Follow.objects.followers(user).count() == 0
|
|
666
664
|
|
|
667
|
-
def test_suggest_organizations_api(self
|
|
665
|
+
def test_suggest_organizations_api(self):
|
|
668
666
|
"""It should suggest organizations"""
|
|
669
667
|
for i in range(3):
|
|
670
668
|
OrganizationFactory(
|
|
671
669
|
name="test-{0}".format(i) if i % 2 else faker.word(), metrics={"followers": i}
|
|
672
670
|
)
|
|
673
671
|
max_follower_organization = OrganizationFactory(name="test-4", metrics={"followers": 10})
|
|
674
|
-
response =
|
|
672
|
+
response = self.get(url_for("api.suggest_organizations", q="tes", size=5))
|
|
675
673
|
assert200(response)
|
|
676
674
|
|
|
677
675
|
assert len(response.json) <= 5
|
|
@@ -686,12 +684,12 @@ class MembershipAPITest(PytestOnlyAPITestCase):
|
|
|
686
684
|
assert "tes" in suggestion["name"]
|
|
687
685
|
assert response.json[0]["id"] == str(max_follower_organization.id)
|
|
688
686
|
|
|
689
|
-
def test_suggest_organizations_with_special_chars(self
|
|
687
|
+
def test_suggest_organizations_with_special_chars(self):
|
|
690
688
|
"""It should suggest organizations with special caracters"""
|
|
691
689
|
for i in range(4):
|
|
692
690
|
OrganizationFactory(name="testé-{0}".format(i) if i % 2 else faker.word())
|
|
693
691
|
|
|
694
|
-
response =
|
|
692
|
+
response = self.get(url_for("api.suggest_organizations", q="testé", size=5))
|
|
695
693
|
assert200(response)
|
|
696
694
|
|
|
697
695
|
assert len(response.json) <= 5
|
|
@@ -704,12 +702,12 @@ class MembershipAPITest(PytestOnlyAPITestCase):
|
|
|
704
702
|
assert "image_url" in suggestion
|
|
705
703
|
assert "testé" in suggestion["name"]
|
|
706
704
|
|
|
707
|
-
def test_suggest_organizations_with_multiple_words(self
|
|
705
|
+
def test_suggest_organizations_with_multiple_words(self):
|
|
708
706
|
"""It should suggest organizations with words"""
|
|
709
707
|
for i in range(4):
|
|
710
708
|
OrganizationFactory(name="mon testé-{0}".format(i) if i % 2 else faker.word())
|
|
711
709
|
|
|
712
|
-
response =
|
|
710
|
+
response = self.get(url_for("api.suggest_organizations", q="mon testé", size=5))
|
|
713
711
|
assert200(response)
|
|
714
712
|
|
|
715
713
|
assert len(response.json) <= 5
|
|
@@ -722,14 +720,14 @@ class MembershipAPITest(PytestOnlyAPITestCase):
|
|
|
722
720
|
assert "image_url" in suggestion
|
|
723
721
|
assert "mon testé" in suggestion["name"]
|
|
724
722
|
|
|
725
|
-
def test_suggest_organizations_with_apostrophe(self
|
|
723
|
+
def test_suggest_organizations_with_apostrophe(self):
|
|
726
724
|
"""It should suggest organizations with words"""
|
|
727
725
|
for i in range(4):
|
|
728
726
|
OrganizationFactory(
|
|
729
727
|
name="Ministère de l'intérieur {0}".format(i) if i % 2 else faker.word()
|
|
730
728
|
)
|
|
731
729
|
|
|
732
|
-
response =
|
|
730
|
+
response = self.get(url_for("api.suggest_organizations", q="Ministère", size=5))
|
|
733
731
|
assert200(response)
|
|
734
732
|
|
|
735
733
|
assert len(response.json) <= 5
|
|
@@ -742,25 +740,25 @@ class MembershipAPITest(PytestOnlyAPITestCase):
|
|
|
742
740
|
assert "image_url" in suggestion
|
|
743
741
|
assert "Ministère" in suggestion["name"]
|
|
744
742
|
|
|
745
|
-
def test_suggest_organizations_api_no_match(self
|
|
743
|
+
def test_suggest_organizations_api_no_match(self):
|
|
746
744
|
"""It should not provide organization suggestion if no match"""
|
|
747
745
|
OrganizationFactory.create_batch(3)
|
|
748
746
|
|
|
749
|
-
response =
|
|
747
|
+
response = self.get(url_for("api.suggest_organizations", q="xxxxxx", size=5))
|
|
750
748
|
assert200(response)
|
|
751
749
|
assert len(response.json) == 0
|
|
752
750
|
|
|
753
|
-
def test_suggest_organizations_api_empty(self
|
|
751
|
+
def test_suggest_organizations_api_empty(self):
|
|
754
752
|
"""It should not provide organization suggestion if no data"""
|
|
755
|
-
response =
|
|
753
|
+
response = self.get(url_for("api.suggest_organizations", q="xxxxxx", size=5))
|
|
756
754
|
assert200(response)
|
|
757
755
|
assert len(response.json) == 0
|
|
758
756
|
|
|
759
|
-
def test_suggest_organizations_homonyms(self
|
|
757
|
+
def test_suggest_organizations_homonyms(self):
|
|
760
758
|
"""It should suggest organizations and not deduplicate homonyms"""
|
|
761
759
|
OrganizationFactory.create_batch(2, name="homonym")
|
|
762
760
|
|
|
763
|
-
response =
|
|
761
|
+
response = self.get(url_for("api.suggest_organizations", q="homonym", size=5))
|
|
764
762
|
assert200(response)
|
|
765
763
|
|
|
766
764
|
assert len(response.json) == 2
|
|
@@ -768,7 +766,7 @@ class MembershipAPITest(PytestOnlyAPITestCase):
|
|
|
768
766
|
for suggestion in response.json:
|
|
769
767
|
assert suggestion["name"] == "homonym"
|
|
770
768
|
|
|
771
|
-
def test_suggest_organizations_acronym(self
|
|
769
|
+
def test_suggest_organizations_acronym(self):
|
|
772
770
|
"""Should suggest organizations based on acronym"""
|
|
773
771
|
|
|
774
772
|
for i in range(3):
|
|
@@ -780,7 +778,7 @@ class MembershipAPITest(PytestOnlyAPITestCase):
|
|
|
780
778
|
max_follower_organization = OrganizationFactory(
|
|
781
779
|
name=faker.word(), acronym="UDATA4", metrics={"followers": 10}
|
|
782
780
|
)
|
|
783
|
-
response =
|
|
781
|
+
response = self.get(url_for("api.suggest_organizations", q="uDaTa", size=5))
|
|
784
782
|
assert200(response)
|
|
785
783
|
|
|
786
784
|
assert len(response.json) == 2
|
|
@@ -796,87 +794,87 @@ class MembershipAPITest(PytestOnlyAPITestCase):
|
|
|
796
794
|
|
|
797
795
|
|
|
798
796
|
class OrganizationDatasetsAPITest(PytestOnlyAPITestCase):
|
|
799
|
-
def test_list_org_datasets(self
|
|
797
|
+
def test_list_org_datasets(self):
|
|
800
798
|
"""Should list organization datasets"""
|
|
801
799
|
org = OrganizationFactory()
|
|
802
800
|
datasets = DatasetFactory.create_batch(3, organization=org)
|
|
803
801
|
|
|
804
|
-
response =
|
|
802
|
+
response = self.get(url_for("api.org_datasets", org=org))
|
|
805
803
|
|
|
806
804
|
assert200(response)
|
|
807
805
|
assert len(response.json["data"]) == len(datasets)
|
|
808
806
|
|
|
809
|
-
def test_list_org_datasets_private(self
|
|
807
|
+
def test_list_org_datasets_private(self):
|
|
810
808
|
"""Should include private datasets when member"""
|
|
811
|
-
user =
|
|
809
|
+
user = self.login()
|
|
812
810
|
member = Member(user=user, role="admin")
|
|
813
811
|
org = OrganizationFactory(members=[member])
|
|
814
812
|
datasets = DatasetFactory.create_batch(3, organization=org, private=True)
|
|
815
813
|
|
|
816
|
-
response =
|
|
814
|
+
response = self.get(url_for("api.org_datasets", org=org))
|
|
817
815
|
|
|
818
816
|
assert200(response)
|
|
819
817
|
assert len(response.json["data"]) == len(datasets)
|
|
820
818
|
|
|
821
|
-
def test_list_org_datasets_hide_private(self
|
|
819
|
+
def test_list_org_datasets_hide_private(self):
|
|
822
820
|
"""Should not include private datasets when not member"""
|
|
823
821
|
org = OrganizationFactory()
|
|
824
822
|
datasets = DatasetFactory.create_batch(3, organization=org)
|
|
825
823
|
DatasetFactory.create_batch(2, organization=org, private=True)
|
|
826
824
|
|
|
827
|
-
response =
|
|
825
|
+
response = self.get(url_for("api.org_datasets", org=org))
|
|
828
826
|
|
|
829
827
|
assert200(response)
|
|
830
828
|
assert len(response.json["data"]) == len(datasets)
|
|
831
829
|
|
|
832
|
-
def test_list_org_datasets_with_size(self
|
|
830
|
+
def test_list_org_datasets_with_size(self):
|
|
833
831
|
"""Should list organization datasets"""
|
|
834
832
|
org = OrganizationFactory()
|
|
835
833
|
DatasetFactory.create_batch(3, organization=org)
|
|
836
834
|
|
|
837
|
-
response =
|
|
835
|
+
response = self.get(url_for("api.org_datasets", org=org, page_size=2))
|
|
838
836
|
|
|
839
837
|
assert200(response)
|
|
840
838
|
assert len(response.json["data"]) == 2
|
|
841
839
|
|
|
842
840
|
|
|
843
841
|
class OrganizationReusesAPITest(PytestOnlyAPITestCase):
|
|
844
|
-
def test_list_org_reuses(self
|
|
842
|
+
def test_list_org_reuses(self):
|
|
845
843
|
"""Should list organization reuses"""
|
|
846
844
|
org = OrganizationFactory()
|
|
847
845
|
reuses = ReuseFactory.create_batch(3, organization=org)
|
|
848
846
|
|
|
849
|
-
response =
|
|
847
|
+
response = self.get(url_for("api.org_reuses", org=org))
|
|
850
848
|
|
|
851
849
|
assert200(response)
|
|
852
850
|
assert len(response.json) == len(reuses)
|
|
853
851
|
|
|
854
|
-
def test_list_org_reuses_private(self
|
|
852
|
+
def test_list_org_reuses_private(self):
|
|
855
853
|
"""Should include private reuses when member"""
|
|
856
|
-
user =
|
|
854
|
+
user = self.login()
|
|
857
855
|
member = Member(user=user, role="admin")
|
|
858
856
|
org = OrganizationFactory(members=[member])
|
|
859
857
|
reuses = ReuseFactory.create_batch(3, organization=org, private=True)
|
|
860
858
|
|
|
861
|
-
response =
|
|
859
|
+
response = self.get(url_for("api.org_reuses", org=org))
|
|
862
860
|
|
|
863
861
|
assert200(response)
|
|
864
862
|
assert len(response.json) == len(reuses)
|
|
865
863
|
|
|
866
|
-
def test_list_org_reuses_hide_private(self
|
|
864
|
+
def test_list_org_reuses_hide_private(self):
|
|
867
865
|
"""Should not include private reuses when not member"""
|
|
868
866
|
org = OrganizationFactory()
|
|
869
867
|
reuses = ReuseFactory.create_batch(3, organization=org)
|
|
870
868
|
ReuseFactory.create_batch(2, organization=org, private=True)
|
|
871
869
|
|
|
872
|
-
response =
|
|
870
|
+
response = self.get(url_for("api.org_reuses", org=org))
|
|
873
871
|
|
|
874
872
|
assert200(response)
|
|
875
873
|
assert len(response.json) == len(reuses)
|
|
876
874
|
|
|
877
875
|
|
|
878
876
|
class OrganizationDiscussionsAPITest(PytestOnlyAPITestCase):
|
|
879
|
-
def test_list_org_discussions(self
|
|
877
|
+
def test_list_org_discussions(self):
|
|
880
878
|
"""Should list organization discussions"""
|
|
881
879
|
user = UserFactory()
|
|
882
880
|
org = OrganizationFactory()
|
|
@@ -887,7 +885,7 @@ class OrganizationDiscussionsAPITest(PytestOnlyAPITestCase):
|
|
|
887
885
|
Discussion.objects.create(subject=reuse, title="", user=user),
|
|
888
886
|
]
|
|
889
887
|
|
|
890
|
-
response =
|
|
888
|
+
response = self.get(url_for("api.org_discussions", org=org))
|
|
891
889
|
|
|
892
890
|
assert200(response)
|
|
893
891
|
assert len(response.json) == len(discussions)
|
|
@@ -899,40 +897,40 @@ class OrganizationDiscussionsAPITest(PytestOnlyAPITestCase):
|
|
|
899
897
|
|
|
900
898
|
class OrganizationBadgeAPITest(PytestOnlyAPITestCase):
|
|
901
899
|
@pytest.fixture(autouse=True)
|
|
902
|
-
def setup_func(self
|
|
900
|
+
def setup_func(self):
|
|
903
901
|
self.factory = badge_factory(Organization)
|
|
904
|
-
self.user =
|
|
902
|
+
self.user = self.login(AdminFactory())
|
|
905
903
|
self.organization = OrganizationFactory()
|
|
906
904
|
|
|
907
|
-
def test_list(self
|
|
908
|
-
response =
|
|
905
|
+
def test_list(self):
|
|
906
|
+
response = self.get(url_for("api.available_organization_badges"))
|
|
909
907
|
assert200(response)
|
|
910
908
|
assert len(response.json) == len(Organization.__badges__)
|
|
911
909
|
for kind, label in Organization.__badges__.items():
|
|
912
910
|
assert kind in response.json
|
|
913
911
|
assert response.json[kind] == label
|
|
914
912
|
|
|
915
|
-
def test_create(self
|
|
913
|
+
def test_create(self):
|
|
916
914
|
data = self.factory.as_dict()
|
|
917
915
|
url = url_for("api.organization_badges", org=self.organization)
|
|
918
916
|
with assert_emit(on_badge_added):
|
|
919
|
-
response =
|
|
917
|
+
response = self.post(url, data)
|
|
920
918
|
assert201(response)
|
|
921
919
|
self.organization.reload()
|
|
922
920
|
assert len(self.organization.badges) == 1
|
|
923
921
|
|
|
924
|
-
def test_create_same(self
|
|
922
|
+
def test_create_same(self):
|
|
925
923
|
data = self.factory.as_dict()
|
|
926
924
|
url = url_for("api.organization_badges", org=self.organization)
|
|
927
925
|
with assert_emit(on_badge_added):
|
|
928
|
-
|
|
926
|
+
self.post(url, data)
|
|
929
927
|
with assert_not_emit(on_badge_added):
|
|
930
|
-
response =
|
|
928
|
+
response = self.post(url, data)
|
|
931
929
|
assert200(response)
|
|
932
930
|
self.organization.reload()
|
|
933
931
|
assert len(self.organization.badges) == 1
|
|
934
932
|
|
|
935
|
-
def test_create_2nd(self
|
|
933
|
+
def test_create_2nd(self):
|
|
936
934
|
# Explicitely setting the kind to avoid collisions given the
|
|
937
935
|
# small number of choices for kinds.
|
|
938
936
|
kinds_keys = list(Organization.__badges__)
|
|
@@ -940,32 +938,32 @@ class OrganizationBadgeAPITest(PytestOnlyAPITestCase):
|
|
|
940
938
|
data = self.factory.as_dict()
|
|
941
939
|
data["kind"] = kinds_keys[1]
|
|
942
940
|
url = url_for("api.organization_badges", org=self.organization)
|
|
943
|
-
response =
|
|
941
|
+
response = self.post(url, data)
|
|
944
942
|
assert201(response)
|
|
945
943
|
self.organization.reload()
|
|
946
944
|
assert len(self.organization.badges) == 2
|
|
947
945
|
|
|
948
|
-
def test_delete(self
|
|
946
|
+
def test_delete(self):
|
|
949
947
|
badge = self.factory()
|
|
950
948
|
self.organization.add_badge(badge.kind)
|
|
951
949
|
self.organization.save()
|
|
952
950
|
url = url_for("api.organization_badge", org=self.organization, badge_kind=str(badge.kind))
|
|
953
951
|
with assert_emit(on_badge_removed):
|
|
954
|
-
response =
|
|
952
|
+
response = self.delete(url)
|
|
955
953
|
assert204(response)
|
|
956
954
|
self.organization.reload()
|
|
957
955
|
assert len(self.organization.badges) == 0
|
|
958
956
|
|
|
959
|
-
def test_delete_404(self
|
|
957
|
+
def test_delete_404(self):
|
|
960
958
|
kind = str(self.factory().kind)
|
|
961
959
|
url = url_for("api.organization_badge", org=self.organization, badge_kind=kind)
|
|
962
|
-
response =
|
|
960
|
+
response = self.delete(url)
|
|
963
961
|
assert404(response)
|
|
964
962
|
|
|
965
963
|
|
|
966
964
|
class OrganizationContactPointsAPITest(PytestOnlyAPITestCase):
|
|
967
|
-
def test_org_contact_points(self
|
|
968
|
-
user =
|
|
965
|
+
def test_org_contact_points(self):
|
|
966
|
+
user = self.login()
|
|
969
967
|
member = Member(user=user, role="admin")
|
|
970
968
|
org = OrganizationFactory(members=[member])
|
|
971
969
|
data = {
|
|
@@ -974,17 +972,17 @@ class OrganizationContactPointsAPITest(PytestOnlyAPITestCase):
|
|
|
974
972
|
"organization": str(org.id),
|
|
975
973
|
"role": "contact",
|
|
976
974
|
}
|
|
977
|
-
response =
|
|
975
|
+
response = self.post(url_for("api.contact_points"), data)
|
|
978
976
|
assert201(response)
|
|
979
977
|
|
|
980
|
-
response =
|
|
978
|
+
response = self.get(url_for("api.org_contact_points", org=org))
|
|
981
979
|
assert200(response)
|
|
982
980
|
|
|
983
981
|
assert response.json["data"][0]["name"] == data["name"]
|
|
984
982
|
assert response.json["data"][0]["email"] == data["email"]
|
|
985
983
|
|
|
986
|
-
def test_org_contact_points_suggest(self
|
|
987
|
-
user =
|
|
984
|
+
def test_org_contact_points_suggest(self):
|
|
985
|
+
user = self.login()
|
|
988
986
|
member = Member(user=user, role="admin")
|
|
989
987
|
org = OrganizationFactory(members=[member])
|
|
990
988
|
data = {
|
|
@@ -993,16 +991,16 @@ class OrganizationContactPointsAPITest(PytestOnlyAPITestCase):
|
|
|
993
991
|
"organization": str(org.id),
|
|
994
992
|
"role": "contact",
|
|
995
993
|
}
|
|
996
|
-
response =
|
|
994
|
+
response = self.post(url_for("api.contact_points"), data)
|
|
997
995
|
assert201(response)
|
|
998
996
|
|
|
999
|
-
response =
|
|
997
|
+
response = self.get(url_for("api.suggest_org_contact_points", org=org, q="mooneywayne"))
|
|
1000
998
|
assert200(response)
|
|
1001
999
|
|
|
1002
1000
|
assert response.json[0]["name"] == data["name"]
|
|
1003
1001
|
assert response.json[0]["email"] == data["email"]
|
|
1004
1002
|
|
|
1005
|
-
response =
|
|
1003
|
+
response = self.get(
|
|
1006
1004
|
url_for("api.suggest_org_contact_points", org=org, q="mooneeejnknywayne")
|
|
1007
1005
|
)
|
|
1008
1006
|
assert200(response)
|
|
@@ -1011,15 +1009,14 @@ class OrganizationContactPointsAPITest(PytestOnlyAPITestCase):
|
|
|
1011
1009
|
|
|
1012
1010
|
|
|
1013
1011
|
class OrganizationCsvExportsTest(PytestOnlyAPITestCase):
|
|
1014
|
-
def test_datasets_csv(self
|
|
1012
|
+
def test_datasets_csv(self):
|
|
1015
1013
|
org = OrganizationFactory()
|
|
1016
1014
|
[DatasetFactory(organization=org, resources=[ResourceFactory()]) for _ in range(3)]
|
|
1017
1015
|
|
|
1018
|
-
response =
|
|
1016
|
+
response = self.get(url_for("api.organization_datasets_csv", org=org))
|
|
1019
1017
|
|
|
1020
1018
|
assert200(response)
|
|
1021
1019
|
assert response.mimetype == "text/csv"
|
|
1022
|
-
assert response.charset == "utf-8"
|
|
1023
1020
|
|
|
1024
1021
|
csvfile = StringIO(response.data.decode("utf-8"))
|
|
1025
1022
|
reader = csv.get_reader(csvfile)
|
|
@@ -1034,7 +1031,7 @@ class OrganizationCsvExportsTest(PytestOnlyAPITestCase):
|
|
|
1034
1031
|
assert "tags" in header
|
|
1035
1032
|
assert "metric.reuses" in header
|
|
1036
1033
|
|
|
1037
|
-
def test_resources_csv(self
|
|
1034
|
+
def test_resources_csv(self):
|
|
1038
1035
|
org = OrganizationFactory()
|
|
1039
1036
|
datasets = [
|
|
1040
1037
|
DatasetFactory(organization=org, resources=[ResourceFactory(), ResourceFactory()])
|
|
@@ -1043,11 +1040,10 @@ class OrganizationCsvExportsTest(PytestOnlyAPITestCase):
|
|
|
1043
1040
|
not_org_dataset = DatasetFactory(resources=[ResourceFactory()])
|
|
1044
1041
|
hidden_dataset = DatasetFactory(private=True)
|
|
1045
1042
|
|
|
1046
|
-
response =
|
|
1043
|
+
response = self.get(url_for("api.organization_datasets_resources_csv", org=org))
|
|
1047
1044
|
|
|
1048
1045
|
assert200(response)
|
|
1049
1046
|
assert response.mimetype == "text/csv"
|
|
1050
|
-
assert response.charset == "utf-8"
|
|
1051
1047
|
|
|
1052
1048
|
csvfile = StringIO(response.data.decode("utf-8"))
|
|
1053
1049
|
reader = csv.get_reader(csvfile)
|
|
@@ -1077,15 +1073,14 @@ class OrganizationCsvExportsTest(PytestOnlyAPITestCase):
|
|
|
1077
1073
|
assert str(hidden_dataset.id) not in dataset_ids
|
|
1078
1074
|
assert str(not_org_dataset.id) not in dataset_ids
|
|
1079
1075
|
|
|
1080
|
-
def test_dataservices_csv(self
|
|
1076
|
+
def test_dataservices_csv(self):
|
|
1081
1077
|
org = OrganizationFactory()
|
|
1082
1078
|
[DataserviceFactory(organization=org) for _ in range(3)]
|
|
1083
1079
|
|
|
1084
|
-
response =
|
|
1080
|
+
response = self.get(url_for("api.organization_dataservices_csv", org=org))
|
|
1085
1081
|
|
|
1086
1082
|
assert200(response)
|
|
1087
1083
|
assert response.mimetype == "text/csv"
|
|
1088
|
-
assert response.charset == "utf-8"
|
|
1089
1084
|
|
|
1090
1085
|
csvfile = StringIO(response.data.decode("utf-8"))
|
|
1091
1086
|
reader = csv.get_reader(csvfile)
|
|
@@ -1101,9 +1096,9 @@ class OrganizationCsvExportsTest(PytestOnlyAPITestCase):
|
|
|
1101
1096
|
assert "metric.views" in header
|
|
1102
1097
|
assert "datasets" in header
|
|
1103
1098
|
|
|
1104
|
-
def test_discussions_csv_content_empty(self
|
|
1099
|
+
def test_discussions_csv_content_empty(self):
|
|
1105
1100
|
organization = OrganizationFactory()
|
|
1106
|
-
response =
|
|
1101
|
+
response = self.get(url_for("api.organization_discussions_csv", org=organization))
|
|
1107
1102
|
assert200(response)
|
|
1108
1103
|
|
|
1109
1104
|
assert response.data.decode("utf8") == (
|
|
@@ -1112,12 +1107,12 @@ class OrganizationCsvExportsTest(PytestOnlyAPITestCase):
|
|
|
1112
1107
|
'"closed_by_organization_id"\r\n'
|
|
1113
1108
|
)
|
|
1114
1109
|
|
|
1115
|
-
def test_discussions_csv_content_filled(self
|
|
1110
|
+
def test_discussions_csv_content_filled(self):
|
|
1116
1111
|
organization = OrganizationFactory()
|
|
1117
1112
|
dataset = DatasetFactory(organization=organization)
|
|
1118
1113
|
user = UserFactory(first_name="John", last_name="Snow")
|
|
1119
1114
|
discussion = DiscussionFactory(subject=dataset, user=user)
|
|
1120
|
-
response =
|
|
1115
|
+
response = self.get(url_for("api.organization_discussions_csv", org=organization))
|
|
1121
1116
|
assert200(response)
|
|
1122
1117
|
|
|
1123
1118
|
headers, data = response.data.decode("utf-8").strip().split("\r\n")
|