131 lines
4.7 KiB
Python
131 lines
4.7 KiB
Python
|
from django.core.exceptions import ValidationError
|
||
|
from rest_framework import serializers
|
||
|
|
||
|
from orchestra.api.serializers import HyperlinkedModelSerializer, RelatedHyperlinkedModelSerializer
|
||
|
from orchestra.contrib.accounts.serializers import AccountSerializerMixin
|
||
|
|
||
|
from .directives import SiteDirective
|
||
|
from .models import Website, Content, WebsiteDirective
|
||
|
from .utils import normurlpath
|
||
|
from .validators import validate_domain_protocol
|
||
|
|
||
|
|
||
|
|
||
|
class RelatedDomainSerializer(AccountSerializerMixin, RelatedHyperlinkedModelSerializer):
|
||
|
class Meta:
|
||
|
model = Website.domains.field.related_model
|
||
|
fields = ('url', 'id', 'name')
|
||
|
|
||
|
|
||
|
class RelatedWebAppSerializer(AccountSerializerMixin, RelatedHyperlinkedModelSerializer):
|
||
|
class Meta:
|
||
|
model = Content.webapp.field.related_model
|
||
|
fields = ('url', 'id', 'name', 'type')
|
||
|
|
||
|
|
||
|
class ContentSerializer(serializers.ModelSerializer):
|
||
|
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)
|
||
|
contents = ContentSerializer(required=False, many=True, source='content_set')
|
||
|
directives = DirectiveSerializer(required=False)
|
||
|
|
||
|
class Meta:
|
||
|
model = Website
|
||
|
fields = ('url', 'id', 'name', 'protocol', 'domains', 'is_active', 'contents', 'directives')
|
||
|
postonly_fields = ('name',)
|
||
|
|
||
|
def validate(self, data):
|
||
|
""" Prevent multiples domains on the same protocol """
|
||
|
# Validate location and directive uniqueness
|
||
|
errors = []
|
||
|
directives = data.get('directives', [])
|
||
|
if directives:
|
||
|
locations = set()
|
||
|
for content in data.get('content_set', []):
|
||
|
location = content.get('path')
|
||
|
if location is not None:
|
||
|
locations.add(normurlpath(location))
|
||
|
values = defaultdict(list)
|
||
|
for name, value in directives.items():
|
||
|
directive = {
|
||
|
'name': name,
|
||
|
'value': value,
|
||
|
}
|
||
|
try:
|
||
|
SiteDirective.get(name).validate_uniqueness(directive, values, locations)
|
||
|
except ValidationError as err:
|
||
|
errors.append(err)
|
||
|
# Validate domain protocol uniqueness
|
||
|
instance = self.instance
|
||
|
for domain in data['domains']:
|
||
|
try:
|
||
|
validate_domain_protocol(instance, domain, data['protocol'])
|
||
|
except ValidationError as err:
|
||
|
errors.append(err)
|
||
|
if errors:
|
||
|
raise ValidationError(errors)
|
||
|
return data
|
||
|
|
||
|
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_directives(self, instance, directives_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()
|
||
|
|
||
|
def update_contents(self, instance, contents_data):
|
||
|
raise NotImplementedError
|
||
|
|
||
|
def update_domains(self, instance, domains_data):
|
||
|
raise NotImplementedError
|
||
|
|
||
|
def update(self, instance, validated_data):
|
||
|
directives_data = validated_data.pop('directives')
|
||
|
domains_data = validated_data.pop('domains')
|
||
|
contents_data = validated_data.pop('content_set')
|
||
|
instance = super(WebsiteSerializer, self).update(instance, validated_data)
|
||
|
self.update_directives(instance, directives_data)
|
||
|
self.update_contents(instance, contents_data)
|
||
|
self.update_domains(instance, domains_data)
|
||
|
return instance
|