Skip to content

Commit

Permalink
Do not allow changing restricted custom fields
Browse files Browse the repository at this point in the history
  • Loading branch information
romcheg committed Dec 13, 2019
1 parent 1229b75 commit d1e0d8c
Show file tree
Hide file tree
Showing 2 changed files with 157 additions and 5 deletions.
31 changes: 28 additions & 3 deletions src/ralph/lib/custom_fields/forms.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from django import forms
from django.contrib.contenttypes.forms import BaseGenericInlineFormSet
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ValidationError
from django.db.models import Q
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import ugettext
Expand All @@ -10,15 +11,38 @@ class CustomFieldValueForm(forms.ModelForm):
class Meta:
fields = ['custom_field', 'value']

def __init__(self, *args, **kwargs):
def __init__(self, request=None, *args, **kwargs):
super().__init__(*args, **kwargs)
self.request = request
self._replace_value_field()

def _replace_value_field(self):
# replace custom field value field with proper one (ex. select)
if self.instance and self.instance.custom_field_id:
self.fields['value'] = self.instance.custom_field.get_form_field()

def clean(self):
clean_data = super().clean()
custom_field = clean_data.get('custom_field')

if custom_field:
if (
custom_field.managing_group is not None and
custom_field.managing_group not in self.request.user.groups.all() # noqa: E501
):
self.add_error(
'custom_field',
ValidationError(
_(
'Only users from {} group can set '
'this custom field.'
).format(custom_field.managing_group.name),
code='invalid'
)
)

return clean_data


class CustomFieldValueWithClearChildrenForm(CustomFieldValueForm):
clear_children = forms.BooleanField(
Expand All @@ -45,9 +69,10 @@ def __init__(
self, data=None, files=None, instance=None, save_as_new=None,
prefix=None, queryset=None, request=None, **kwargs
):
self.request = request
queryset = queryset.filter(
Q(custom_field__managing_group__isnull=True) |
Q(custom_field__managing_group__in=request.user.groups.all())
Q(custom_field__managing_group__in=self.request.user.groups.all())
)

super().__init__(
Expand All @@ -56,7 +81,7 @@ def __init__(
)

def _construct_form(self, i, **kwargs):
form = super()._construct_form(i, **kwargs)
form = super()._construct_form(i, request=self.request, **kwargs)
# fix for https://code.djangoproject.com/ticket/12028, together with
# model's `_get_unique_checks`, which removes 'content_type' and
# 'object_id' fields from excluded list for unique validation
Expand Down
131 changes: 129 additions & 2 deletions src/ralph/lib/custom_fields/tests/test_admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
from django.contrib.contenttypes.models import ContentType
from django.core.urlresolvers import reverse
from django.test import RequestFactory, TestCase
from rest_framework.status import HTTP_200_OK

from ralph.accounts.tests.factories import GroupFactory

from ..models import CustomField, CustomFieldTypes, CustomFieldValue
from .models import ModelA, ModelB, SomeModel

Expand Down Expand Up @@ -258,7 +260,7 @@ def test_custom_field_not_in_form_for_nonmatching_managing_group(self):

filled_in_custom_field_forms = [
form
for form in response.context_data['inline_admin_formsets'][0].formset.forms
for form in response.context_data['inline_admin_formsets'][0].formset.forms # noqa: E501
if form.fields['id'].initial is not None
]

Expand All @@ -284,7 +286,7 @@ def test_custom_field_in_form_for_matching_managing_group(self):

filled_in_custom_field_forms = [
form
for form in response.context_data['inline_admin_formsets'][0].formset.forms
for form in response.context_data['inline_admin_formsets'][0].formset.forms # noqa: E501
if form.fields['id'].initial is not None
]

Expand All @@ -295,3 +297,128 @@ def test_custom_field_in_form_for_matching_managing_group(self):
self.cfv1.id,
form.fields['id'].initial
)

def test_add_new_custom_field_value_succeeds_with_matching_managing_group(self): # noqa: E501
group = GroupFactory()

self.user.groups.add(group)
self.custom_field_choices.managing_group = group

self.user.save()
self.custom_field_choices.save()

data = {
'id': self.sm1.id,
'name': self.sm1.name,
}
data_custom_fields = {
'TOTAL_FORMS': 3,
'INITIAL_FORMS': 1,
'0-id': self.cfv1.id,
'0-custom_field': self.custom_field_str.id,
'0-value': 'sample_value',
'1-id': '',
'1-custom_field': self.custom_field_choices.id,
'1-value': 'qwerty',
}
data.update(self._prepare_inline_data(data_custom_fields))

response = self.client.post(
self.sm1.get_absolute_url(),
data,
follow=True
)
self.assertEqual(response.status_code, HTTP_200_OK)

custom_field_qs = CustomFieldValue.objects.filter(
object_id=self.sm1.id,
content_type=ContentType.objects.get_for_model(SomeModel),
custom_field=self.custom_field_choices,
value='qwerty'
)
self.assertTrue(custom_field_qs.exists())

def test_add_new_custom_field_value_fails_with_nonmatching_managing_group(self): # noqa: E501
group = GroupFactory()

self.custom_field_choices.managing_group = group
self.custom_field_choices.save()

data = {
'id': self.sm1.id,
'name': self.sm1.name,
}
data_custom_fields = {
'TOTAL_FORMS': 3,
'INITIAL_FORMS': 1,
'0-id': self.cfv1.id,
'0-custom_field': self.custom_field_str.id,
'0-value': 'sample_value',
'1-id': '',
'1-custom_field': self.custom_field_choices.id,
'1-value': 'qwerty',
}
data.update(self._prepare_inline_data(data_custom_fields))

response = self.client.post(
self.sm1.get_absolute_url(),
data,
follow=True
)
self.assertEqual(response.status_code, HTTP_200_OK)

expected_error_message = (
'<ul class="errorlist"><li>'
'Only users from {} group can set this custom field.</li></ul>'
).format(group.name)
self.assertIn('errors', response.context_data)
self.assertIn(expected_error_message, response.context_data['errors'])

custom_field_qs = CustomFieldValue.objects.filter(
object_id=self.sm1.id,
content_type=ContentType.objects.get_for_model(SomeModel),
custom_field=self.custom_field_choices,
value='qwerty'
)
self.assertFalse(custom_field_qs.exists())

def test_edit_custom_field_value_fails_with_nonmatching_managing_group(self): # noqa: E501
group = GroupFactory()

self.custom_field_str.managing_group = group
self.custom_field_str.save()

data = {
'id': self.sm1.id,
'name': self.sm1.name,
}
data_custom_fields = {
'TOTAL_FORMS': 2,
'INITIAL_FORMS': 1,
'0-id': self.cfv1.id,
'0-custom_field': self.custom_field_str.id,
'0-value': 'NEW-VALUE',
}
data.update(self._prepare_inline_data(data_custom_fields))

response = self.client.post(
self.sm1.get_absolute_url(),
data,
follow=True
)
self.assertEqual(response.status_code, HTTP_200_OK)

expected_error_message = (
'<ul class="errorlist"><li>'
'Only users from {} group can set this custom field.</li></ul>'
).format(group.name)
self.assertIn('errors', response.context_data)
self.assertIn(expected_error_message, response.context_data['errors'])

custom_field_qs = CustomFieldValue.objects.filter(
object_id=self.sm1.id,
content_type=ContentType.objects.get_for_model(SomeModel),
custom_field=self.custom_field_str,
value='sample_value'
)
self.assertTrue(custom_field_qs.exists())

0 comments on commit d1e0d8c

Please sign in to comment.