|
1 | 1 | from datetime import date |
2 | 2 |
|
| 3 | +import django |
3 | 4 | from django.contrib.auth import get_user_model |
4 | 5 | from django.contrib.auth.models import Permission |
5 | 6 | from django.urls import reverse |
6 | 7 | from swapper import load_model |
7 | 8 |
|
| 9 | +from openwisp_users.multitenancy import SHARED_SYSTEMWIDE_LABEL |
| 10 | + |
8 | 11 | Organization = load_model('openwisp_users', 'Organization') |
9 | 12 | OrganizationOwner = load_model('openwisp_users', 'OrganizationOwner') |
10 | 13 | OrganizationUser = load_model('openwisp_users', 'OrganizationUser') |
@@ -236,9 +239,82 @@ def _test_recoverlist_operator_403(self, app_label, model_label): |
236 | 239 | ) |
237 | 240 | self.assertEqual(response.status_code, 403) |
238 | 241 |
|
239 | | - def _get_autocomplete_view_path(self, app_label, model_name, field_name): |
| 242 | + def _test_org_admin_create_shareable_object( |
| 243 | + self, path, payload, model, expected_count=0, error_message=None, user=None |
| 244 | + ): |
| 245 | + """ |
| 246 | + Verifies a non-superuser cannot create a shareable object |
| 247 | + """ |
| 248 | + if not user: |
| 249 | + user = self._create_administrator(organizations=[self._get_org()]) |
| 250 | + self.client.force_login(user) |
| 251 | + response = self.client.post( |
| 252 | + path, |
| 253 | + data=payload, |
| 254 | + follow=True, |
| 255 | + ) |
| 256 | + error_message = error_message or ( |
| 257 | + '<div class="form-row errors field-organization">\n' |
| 258 | + ' <ul class="errorlist"{}>' |
| 259 | + '<li>This field is required.</li></ul>' |
| 260 | + ).format(' id="id_organization_error"' if django.VERSION >= (5, 2) else '') |
| 261 | + self.assertContains(response, error_message) |
| 262 | + self.assertEqual(model.objects.count(), expected_count) |
| 263 | + |
| 264 | + def _test_org_admin_view_shareable_object( |
| 265 | + self, path, user=None, expected_element=None |
| 266 | + ): |
| 267 | + """ |
| 268 | + Verifies a non-superuser can view a shareable object |
| 269 | + """ |
| 270 | + if not user: |
| 271 | + user = self._create_administrator(organizations=[self._get_org()]) |
| 272 | + self.client.force_login(user) |
| 273 | + response = self.client.get(path, follow=True) |
| 274 | + self.assertEqual(response.status_code, 200) |
| 275 | + if not expected_element: |
| 276 | + expected_element = ( |
| 277 | + '<div class="form-row field-organization">\n\n\n<div>\n\n' |
| 278 | + '<div class="flex-container">\n\n' |
| 279 | + '<label>Organization:</label>\n\n' |
| 280 | + '<div class="readonly">-</div>\n\n\n' |
| 281 | + '</div>\n\n</div>\n\n\n</div>' |
| 282 | + ) |
| 283 | + self.assertContains(response, expected_element, html=True) |
| 284 | + |
| 285 | + def _test_object_organization_fk_autocomplete_view( |
| 286 | + self, |
| 287 | + model, |
| 288 | + ): |
| 289 | + app_label = model._meta.app_label |
| 290 | + model_name = model._meta.model_name |
| 291 | + path = self._get_autocomplete_view_path(app_label, model_name, 'organization') |
| 292 | + org = self._get_org() |
| 293 | + admin = User.objects.filter(is_superuser=True).first() |
| 294 | + if not admin: |
| 295 | + admin = self._create_admin() |
| 296 | + org_admin = self._create_administrator(organizations=[org]) |
| 297 | + |
| 298 | + with self.subTest('Org admin should only see their own org'): |
| 299 | + self.client.force_login(org_admin) |
| 300 | + response = self.client.get(path) |
| 301 | + self.assertEqual(response.status_code, 200) |
| 302 | + self.assertContains(response, org.name) |
| 303 | + self.assertNotContains(response, SHARED_SYSTEMWIDE_LABEL) |
| 304 | + |
| 305 | + with self.subTest('Superuser should see all orgs and shared label'): |
| 306 | + self.client.force_login(admin) |
| 307 | + response = self.client.get(path) |
| 308 | + self.assertEqual(response.status_code, 200) |
| 309 | + self.assertContains(response, org.name) |
| 310 | + self.assertContains(response, SHARED_SYSTEMWIDE_LABEL) |
| 311 | + |
| 312 | + def _get_autocomplete_view_path( |
| 313 | + self, app_label, model_name, field_name, is_filter=False |
| 314 | + ): |
240 | 315 | path = reverse('admin:ow-auto-filter') |
241 | 316 | return ( |
242 | 317 | f'{path}?app_label={app_label}' |
243 | 318 | f'&model_name={model_name}&field_name={field_name}' |
| 319 | + '{}'.format('&is_filter=true' if is_filter else '') |
244 | 320 | ) |
0 commit comments