Browse Source

Fixes #1226: Improve validation for custom field values submitted via the API

Jeremy Stretch 8 years ago
parent
commit
293dbd8a8b
2 changed files with 26 additions and 5 deletions
  1. 21 4
      netbox/extras/api/customfields.py
  2. 5 1
      netbox/extras/models.py

+ 21 - 4
netbox/extras/api/customfields.py

@@ -1,4 +1,5 @@
 from __future__ import unicode_literals
+from datetime import datetime
 
 from rest_framework import serializers
 from rest_framework.exceptions import ValidationError
@@ -6,7 +7,9 @@ from rest_framework.exceptions import ValidationError
 from django.contrib.contenttypes.models import ContentType
 from django.db import transaction
 
-from extras.models import CF_TYPE_SELECT, CustomField, CustomFieldChoice, CustomFieldValue
+from extras.models import (
+    CF_TYPE_BOOLEAN, CF_TYPE_DATE, CF_TYPE_SELECT, CustomField, CustomFieldChoice, CustomFieldValue,
+)
 
 
 #
@@ -25,16 +28,30 @@ class CustomFieldsSerializer(serializers.BaseSerializer):
 
         for field_name, value in data.items():
 
+            cf = custom_fields[field_name]
+
             # Validate custom field name
             if field_name not in custom_fields:
                 raise ValidationError("Invalid custom field for {} objects: {}".format(content_type, field_name))
 
+            # Validate boolean
+            if cf.type == CF_TYPE_BOOLEAN and value not in [True, False, 1, 0]:
+                raise ValidationError("Invalid value for boolean field {}: {}".format(field_name, value))
+
+            # Validate date
+            if cf.type == CF_TYPE_DATE:
+                try:
+                    datetime.strptime(value, '%Y-%m-%d')
+                except ValueError:
+                    raise ValidationError("Invalid date for field {}: {}. (Required format is YYYY-MM-DD.)".format(
+                        field_name, value
+                    ))
+
             # Validate selected choice
-            cf = custom_fields[field_name]
             if cf.type == CF_TYPE_SELECT:
                 valid_choices = [c.pk for c in cf.choices.all()]
                 if value not in valid_choices:
-                    raise ValidationError("Invalid choice ({}) for field {}".format(value, field_name))
+                    raise ValidationError("Invalid choice for field {}: {}".format(field_name, value))
 
         # Check for missing required fields
         missing_fields = []
@@ -87,7 +104,7 @@ class CustomFieldModelSerializer(serializers.ModelSerializer):
                 field=custom_field,
                 obj_type=content_type,
                 obj_id=instance.pk,
-                defaults={'serialized_value': value},
+                defaults={'serialized_value': custom_field.serialize_value(value)},
             )
 
     def create(self, validated_data):

+ 5 - 1
netbox/extras/models.py

@@ -139,7 +139,11 @@ class CustomField(models.Model):
         if self.type == CF_TYPE_BOOLEAN:
             return str(int(bool(value)))
         if self.type == CF_TYPE_DATE:
-            return value.strftime('%Y-%m-%d')
+            # Could be date/datetime object or string
+            try:
+                return value.strftime('%Y-%m-%d')
+            except AttributeError:
+                return value
         if self.type == CF_TYPE_SELECT:
             # Could be ModelChoiceField or TypedChoiceField
             return str(value.id) if hasattr(value, 'id') else str(value)