diff --git a/beat/web/experiments/serializers.py b/beat/web/experiments/serializers.py index af135eac88f9e2957bd77b40ae3ca4b3d7610186..d59d45e6c846f07d1a29ba65c8e2b176d8ccf558 100755 --- a/beat/web/experiments/serializers.py +++ b/beat/web/experiments/serializers.py @@ -25,18 +25,115 @@ # # ############################################################################### +import simplejson as json + +import beat.core + +from datetime import datetime + from rest_framework import serializers + from django.contrib.humanize.templatetags.humanize import naturaltime +from django.db.models import CharField, Value as V +from django.db.models.functions import Concat + from ..common.serializers import ShareableSerializer from ..common.fields import JSONSerializerField +from ..common.utils import validate_restructuredtext +from ..common.exceptions import ContributionCreationError + from ..ui.templatetags.markup import restructuredtext +from ..toolchains.models import Toolchain + from .models import Experiment, Block -from datetime import datetime -import simplejson as json +# ---------------------------------------------------------- + + +class ExperimentCreationSerializer(serializers.ModelSerializer): + declaration = JSONSerializerField() + description = serializers.CharField(required=False, allow_blank=True) + fork_of = serializers.JSONField(required=False) + toolchain = serializers.CharField() + + class Meta: + model = Experiment + beat_core_class = beat.core.experiment + fields = [ + "name", + "short_description", + "description", + "declaration", + "toolchain", + "fork_of", + ] + + def toolchain_queryset(self): + user = self.context.get("user") + return Toolchain.objects.for_user(user, True).annotate( + full_name=Concat( + "author__username", + V("/"), + "name", + V("/"), + "version", + output_field=CharField(), + ) + ) + + def validate_name(self, name): + # sanitize_name is a static method of Versionable models but Experiment + # is currently not such a model + return Toolchain.sanitize_name(name) + + def validate_description(self, description): + if description.find("\\") >= 0: # was escaped, unescape + description = description.decode("string_escape") + validate_restructuredtext(description) + return description + + def validate_toolchain(self, toolchain): + if not self.toolchain_queryset().filter(full_name=toolchain).exists(): + raise serializers.ValidationError("Invalid toolchain: {}".format(toolchain)) + + return toolchain + + def validate(self, data): + user = self.context.get("user") + name = data["name"] + toolchain = data["toolchain"] + + if self.Meta.model.objects.filter( + author=user, + name=name, + toolchain=self.toolchain_queryset().get(full_name=toolchain), + ).exists(): + raise serializers.ValidationError( + "{} {} with toolchain {} already exists on this account".format( + self.Meta.model.__name__.lower(), name, toolchain + ) + ) + + return data + + def create(self, validated_data): + toolchain = self.toolchain_queryset().get(full_name=validated_data["toolchain"]) + + experiment, _, errors = Experiment.objects.create_experiment( + author=self.context.get("user"), + toolchain=toolchain, + name=validated_data["name"], + short_description=validated_data.get("short_description", ""), + description=validated_data.get("description", ""), + declaration=validated_data["declaration"], + ) + + if errors: + raise ContributionCreationError(errors) + return experiment # ----------------------------------------------------------