from django.core.exceptions import ValidationError from django.shortcuts import get_object_or_404 from rest_framework import serializers from orchestra.api.serializers import HyperlinkedModelSerializer from orchestra.contrib.accounts.serializers import AccountSerializerMixin from .models import Website, Content, WebsiteDirective from .validators import validate_domain_protocol class RelatedDomainSerializer(AccountSerializerMixin, serializers.HyperlinkedModelSerializer): class Meta: model = Website.domains.field.rel.to fields = ('url', 'id', 'name') def from_native(self, data, files=None): queryset = self.opts.model.objects.filter(account=self.account) return get_object_or_404(queryset, name=data['name']) class RelatedWebAppSerializer(AccountSerializerMixin, serializers.HyperlinkedModelSerializer): class Meta: model = Content.webapp.field.rel.to fields = ('url', 'id', 'name', 'type') def from_native(self, data, files=None): queryset = self.opts.model.objects.filter(account=self.account) return get_object_or_404(queryset, name=data['name']) class ContentSerializer(serializers.HyperlinkedModelSerializer): webapp = RelatedWebAppSerializer() class Meta: model = Content fields = ('webapp', 'path') def get_identity(self, data): return '%s-%s' % (data.get('website'), data.get('path')) class DirectiveSerializer(serializers.ModelSerializer): class Meta: model = WebsiteDirective fields = ('name', 'value') def to_representation(self, instance): return {prop.name: prop.value for prop in instance.all()} def to_internal_value(self, data): return data class WebsiteSerializer(AccountSerializerMixin, HyperlinkedModelSerializer): domains = RelatedDomainSerializer(many=True, required=False) #allow_add_remove=True contents = ContentSerializer(required=False, many=True, #allow_add_remove=True, source='content_set') directives = DirectiveSerializer(required=False) class Meta: model = Website fields = ('url', 'id', 'name', 'protocol', 'domains', 'is_active', 'contents', 'directives') postonly_fileds = ('name',) def full_clean(self, instance): """ Prevent multiples domains on the same protocol """ for domain in instance._m2m_data['domains']: try: validate_domain_protocol(instance, domain, instance.protocol) except ValidationError as e: # TODO not sure about this one self.add_error(None, e) return instance def create(self, validated_data): directives_data = validated_data.pop('directives') webapp = super(WebsiteSerializer, self).create(validated_data) for key, value in directives_data.items(): WebsiteDirective.objects.create(webapp=webapp, name=key, value=value) return webap def update(self, instance, validated_data): directives_data = validated_data.pop('directives') instance = super(WebsiteSerializer, self).update(instance, validated_data) existing = {} for obj in instance.directives.all(): existing[obj.name] = obj posted = set() for key, value in directives_data.items(): posted.add(key) try: directive = existing[key] except KeyError: directive = instance.directives.create(name=key, value=value) else: if directive.value != value: directive.value = value directive.save(update_fields=('value',)) for to_delete in set(existing.keys())-posted: existing[to_delete].delete() return instance