from django.core.exceptions import ValidationError as DjangoValidationError from rest_framework import serializers from rest_framework.exceptions import ValidationError from normandy.recipes.models import RecipeRevision from normandy.studies.models import Extension class ExtensionSerializer(serializers.ModelSerializer): xpi = serializers.FileField() class Meta: model = Extension fields = ["id", "name", "xpi", "extension_id", "version", "hash", "hash_algorithm"] read_only_fields = ["extension_id", "version", "hash", "hash_algorithm"] def is_valid(self, raise_exception=False): super().is_valid(raise_exception=raise_exception) if "xpi" in self.validated_data: try: Extension(**self.validated_data).populate_metadata() except DjangoValidationError as ex: self._validated_data = {} for field in ex.message_dict: self._errors.update({field: ex.message_dict[field][0]}) if self._errors and raise_exception: raise ValidationError(self.errors) return not bool(self._errors) def update(self, instance, validated_data): revisions = RecipeRevision.objects.filter(action__name="opt-out-study").exclude( latest_for_recipe=None, approved_for_recipe=None ) for r in revisions: if r.arguments.get("extensionId") == instance.id: raise ValidationError("Extension cannot be updated while in use by a recipe.") return super().update(instance, validated_data)