|
| 1 | +import json |
| 2 | + |
1 | 3 | from django import forms |
2 | 4 | from django.conf import settings |
3 | 5 | from django.contrib.auth import password_validation |
|
13 | 15 | from users.constants import * |
14 | 16 | from users.models import * |
15 | 17 | from utilities.data import flatten_dict |
16 | | -from utilities.forms.fields import ContentTypeMultipleChoiceField, DynamicModelMultipleChoiceField |
| 18 | +from utilities.forms.fields import ( |
| 19 | + ContentTypeMultipleChoiceField, |
| 20 | + DynamicModelMultipleChoiceField, |
| 21 | + JSONField, |
| 22 | +) |
17 | 23 | from utilities.forms.rendering import FieldSet |
18 | 24 | from utilities.forms.widgets import DateTimePicker, SplitMultiSelectWidget |
19 | 25 | from utilities.permissions import qs_filter_from_constraints |
@@ -316,46 +322,62 @@ class ObjectPermissionForm(forms.ModelForm): |
316 | 322 | required=False, |
317 | 323 | queryset=Group.objects.all() |
318 | 324 | ) |
| 325 | + constraints = JSONField( |
| 326 | + required=False, |
| 327 | + label=_('Constraints'), |
| 328 | + help_text=_( |
| 329 | + 'JSON expression of a queryset filter that will return only permitted objects. Leave null ' |
| 330 | + 'to match all objects of this type. A list of multiple objects will result in a logical OR ' |
| 331 | + 'operation.' |
| 332 | + ), |
| 333 | + ) |
319 | 334 |
|
320 | 335 | fieldsets = ( |
321 | 336 | FieldSet('name', 'description', 'enabled'), |
322 | 337 | FieldSet('can_view', 'can_add', 'can_change', 'can_delete', 'actions', name=_('Actions')), |
323 | 338 | FieldSet('object_types', name=_('Objects')), |
324 | 339 | FieldSet('groups', 'users', name=_('Assignment')), |
325 | | - FieldSet('constraints', name=_('Constraints')) |
| 340 | + FieldSet('constraints', name=_('Constraints')), |
326 | 341 | ) |
327 | 342 |
|
328 | 343 | class Meta: |
329 | 344 | model = ObjectPermission |
330 | 345 | fields = [ |
331 | 346 | 'name', 'description', 'enabled', 'object_types', 'users', 'groups', 'constraints', 'actions', |
332 | 347 | ] |
333 | | - help_texts = { |
334 | | - 'constraints': _( |
335 | | - 'JSON expression of a queryset filter that will return only permitted objects. Leave null ' |
336 | | - 'to match all objects of this type. A list of multiple objects will result in a logical OR ' |
337 | | - 'operation.' |
338 | | - ) |
339 | | - } |
340 | 348 |
|
341 | 349 | def __init__(self, *args, **kwargs): |
342 | 350 | super().__init__(*args, **kwargs) |
343 | 351 |
|
344 | 352 | # Make the actions field optional since the form uses it only for non-CRUD actions |
345 | 353 | self.fields['actions'].required = False |
346 | 354 |
|
347 | | - # Populate assigned users and groups |
| 355 | + # Prepare the appropriate fields when editing an existing ObjectPermission |
348 | 356 | if self.instance.pk: |
| 357 | + # Populate assigned users and groups |
349 | 358 | self.fields['groups'].initial = self.instance.groups.values_list('id', flat=True) |
350 | 359 | self.fields['users'].initial = self.instance.users.values_list('id', flat=True) |
351 | 360 |
|
352 | | - # Check the appropriate checkboxes when editing an existing ObjectPermission |
353 | | - if self.instance.pk: |
| 361 | + # Check the appropriate checkboxes when editing an existing ObjectPermission |
354 | 362 | for action in ['view', 'add', 'change', 'delete']: |
355 | 363 | if action in self.instance.actions: |
356 | 364 | self.fields[f'can_{action}'].initial = True |
357 | 365 | self.instance.actions.remove(action) |
358 | 366 |
|
| 367 | + # Populate initial data for a new ObjectPermission |
| 368 | + elif self.initial: |
| 369 | + # Handle cloned objects - actions come from initial data (URL parameters) |
| 370 | + if 'actions' in self.initial: |
| 371 | + if cloned_actions := self.initial['actions']: |
| 372 | + for action in ['view', 'add', 'change', 'delete']: |
| 373 | + if action in cloned_actions: |
| 374 | + self.fields[f'can_{action}'].initial = True |
| 375 | + self.initial['actions'].remove(action) |
| 376 | + # Convert data delivered via initial data to JSON data |
| 377 | + if 'constraints' in self.initial: |
| 378 | + if type(self.initial['constraints']) is str: |
| 379 | + self.initial['constraints'] = json.loads(self.initial['constraints']) |
| 380 | + |
359 | 381 | def clean(self): |
360 | 382 | super().clean() |
361 | 383 |
|
|
0 commit comments