예제 #1
0
class HearingSerializer(serializers.ModelSerializer):
    labels = LabelSerializer(many=True, read_only=True)
    images = HearingImageSerializer.get_field_serializer(many=True, read_only=True)
    sections = serializers.SerializerMethodField()
    comments = HearingCommentSerializer.get_field_serializer(many=True, read_only=True)
    commenting = EnumField(enum_type=Commenting)
    geojson = JSONField()

    def get_sections(self, hearing):
        queryset = hearing.sections.all()
        if not hearing.closed:
            queryset = queryset.exclude(type__identifier=InitialSectionType.CLOSURE_INFO)

        serializer = SectionFieldSerializer(many=True, read_only=True)
        serializer.bind('sections', self)  # this is needed to get context in the serializer
        return serializer.to_representation(queryset)

    class Meta:
        model = Hearing
        fields = [
            'abstract', 'title', 'id', 'borough', 'n_comments',
            'commenting', 'published',
            'labels', 'open_at', 'close_at', 'created_at',
            'servicemap_url', 'images', 'sections', 'images',
            'closed', 'comments', 'geojson'
        ]
예제 #2
0
class SectionSerializer(serializers.ModelSerializer, TranslatableSerializer):
    """
    Serializer for section instance.
    """
    images = PublicFilteredImageField(serializer_class=SectionImageSerializer)
    type = serializers.SlugRelatedField(slug_field='identifier', read_only=True)
    type_name_singular = serializers.SlugRelatedField(source='type', slug_field='name_singular', read_only=True)
    type_name_plural = serializers.SlugRelatedField(source='type', slug_field='name_plural', read_only=True)
    commenting = EnumField(enum_type=Commenting)
    voting = EnumField(enum_type=Commenting)

    class Meta:
        model = Section
        fields = [
            'id', 'type', 'commenting', 'voting', 'published',
            'title', 'abstract', 'content', 'created_at', 'images', 'n_comments',
            'type_name_singular', 'type_name_plural',
            'plugin_identifier', 'plugin_data', 'plugin_iframe_url', 'plugin_fullscreen',
        ]
예제 #3
0
class SectionSerializer(serializers.ModelSerializer):
    """
    Serializer for section instance.
    """
    images = SectionImageSerializer.get_field_serializer(many=True,
                                                         read_only=True)
    type = serializers.SlugRelatedField(slug_field='identifier',
                                        read_only=True)
    type_name_singular = serializers.SlugRelatedField(
        source='type', slug_field='name_singular', read_only=True)
    type_name_plural = serializers.SlugRelatedField(source='type',
                                                    slug_field='name_plural',
                                                    read_only=True)
    commenting = EnumField(enum_type=Commenting)

    class Meta:
        model = Section
        fields = [
            'id', 'type', 'commenting', 'published', 'title', 'abstract',
            'content', 'created_at', 'created_by', 'images', 'n_comments',
            'plugin_identifier', 'plugin_data', 'type_name_singular',
            'type_name_plural'
        ]
예제 #4
0
def test_enum():
    ef = EnumField(enum_type=PeculiarEnum)
    assert ef.to_representation(PeculiarEnum.COOL) == "cool"
    assert ef.to_representation(PeculiarEnum.HOT) == "hot"
    assert ef.to_representation(PeculiarEnum.BLEGBLAGPLEPLOP) == "foo"
    assert ef.to_representation(None) == None
    assert ef.to_internal_value("cool") == PeculiarEnum.COOL
    assert ef.to_internal_value("CooL") == PeculiarEnum.COOL
    assert ef.to_internal_value("HOT") == PeculiarEnum.HOT
    assert ef.to_internal_value(1) == PeculiarEnum.COOL
    assert ef.to_internal_value("100") == PeculiarEnum.HOT
    assert ef.to_internal_value("foo") == PeculiarEnum.BLEGBLAGPLEPLOP
    assert ef.to_internal_value("fOO") == PeculiarEnum.BLEGBLAGPLEPLOP
    assert ef.to_internal_value("BLEGBLAGPLEPLOP") == PeculiarEnum.BLEGBLAGPLEPLOP
    with pytest.raises(ValidationError):
        ef.to_internal_value("jmsdfkgi")
예제 #5
0
class SectionCreateUpdateSerializer(serializers.ModelSerializer, TranslatableSerializer):
    """
    Serializer for section create/update.
    """
    id = serializers.CharField(required=False)
    type = serializers.SlugRelatedField(slug_field='identifier', queryset=SectionType.objects.all())
    commenting = EnumField(enum_type=Commenting)

    # this field is used only for incoming data validation, outgoing data is added manually
    # in to_representation()
    images = serializers.ListField(child=serializers.DictField(), write_only=True)

    class Meta:
        model = Section
        fields = [
            'id', 'type', 'commenting', 'published',
            'title', 'abstract', 'content',
            'plugin_identifier', 'plugin_data',
            'images',
        ]

    @transaction.atomic()
    def create(self, validated_data):
        images_data = validated_data.pop('images', [])
        section = super().create(validated_data)
        self._handle_images(section, images_data)
        return section

    @transaction.atomic()
    def update(self, instance, validated_data):
        images_data = validated_data.pop('images', [])
        section = super().update(instance, validated_data)
        self._handle_images(section, images_data)
        return section

    def validate_images(self, data):
        for index, image_data in enumerate(data):
            pk = image_data.get('id')
            image_data['ordering'] = index
            serializer_params = {'data': image_data}

            if pk:
                try:
                    image = self.instance.images.get(pk=pk)
                except SectionImage.DoesNotExist:
                    raise ValidationError('The Section does not have an image with ID %s' % pk)

                serializer_params['instance'] = image

            serializer = SectionImageCreateUpdateSerializer(**serializer_params)
            serializer.is_valid(raise_exception=True)

            # save serializer in data so it can be used when handling the images
            image_data['serializer'] = serializer

        return data

    def _handle_images(self, section, data):
        new_image_ids = set()

        for image_data in data:
            serializer = image_data.pop('serializer')
            image = serializer.save(section=section)
            new_image_ids.add(image.id)

        for image in section.images.exclude(id__in=new_image_ids):
            image.soft_delete()

        return section

    def to_representation(self, instance):
        data = super().to_representation(instance)
        data['images'] = SectionImageSerializer(
            instance.images.all(),
            many=True,
            context=self.context,
        ).data
        return data
예제 #6
0
class SectionCreateUpdateSerializer(serializers.ModelSerializer,
                                    TranslatableSerializer):
    """
    Serializer for section create/update.
    """
    id = serializers.CharField(required=False)
    type = serializers.SlugRelatedField(slug_field='identifier',
                                        queryset=SectionType.objects.all())
    commenting = EnumField(enum_type=Commenting)

    # this field is used only for incoming data validation, outgoing data is added manually
    # in to_representation()
    images = serializers.ListField(child=serializers.DictField(),
                                   write_only=True)
    questions = serializers.ListField(child=serializers.DictField(),
                                      write_only=True,
                                      required=False)
    files = serializers.ListField(child=serializers.DictField(),
                                  write_only=True,
                                  required=False)

    class Meta:
        model = Section
        fields = [
            'id',
            'type',
            'commenting',
            'title',
            'abstract',
            'content',
            'plugin_identifier',
            'plugin_data',
            'images',
            'questions',
            'files',
            'ordering',
        ]

    @transaction.atomic()
    def create(self, validated_data):
        images_data = validated_data.pop('images', [])
        polls_data = validated_data.pop('questions', [])
        files_data = validated_data.pop('files', [])
        section = super().create(validated_data)
        self._handle_images(section, images_data)
        self._handle_questions(section, polls_data)
        self._handle_files(section, files_data)
        return section

    @transaction.atomic()
    def update(self, instance, validated_data):
        images_data = validated_data.pop('images', [])
        polls_data = validated_data.pop('questions', [])
        files_data = validated_data.pop('files', [])
        section = super().update(instance, validated_data)
        self._handle_images(section, images_data)
        self._handle_questions(section, polls_data)
        self._handle_files(section, files_data)
        return section

    def validate_images(self, data):
        for index, image_data in enumerate(data):
            pk = image_data.get('id')
            image_data['ordering'] = index
            serializer_params = {'data': image_data}

            if pk:
                try:
                    image = self.instance.images.get(pk=pk)
                except SectionImage.DoesNotExist:
                    raise ValidationError(
                        'The Section does not have an image with ID %s' % pk)

                serializer_params['instance'] = image

            serializer = SectionImageCreateUpdateSerializer(
                **serializer_params)
            serializer.is_valid(raise_exception=True)

            # save serializer in data so it can be used when handling the images
            image_data['serializer'] = serializer

        return data

    def validate_files(self, data):
        for index, file_data in enumerate(data):
            pk = file_data.get('id')
            file_data['ordering'] = index
            serializer_params = {
                'data': file_data,
                'context': {
                    'request': self.context['request']
                }
            }

            if pk:
                try:
                    # only allow orphan files or files within this section already
                    file = SectionFile.objects.filter(
                        Q(section=None)
                        | (Q(section=self.instance))).get(pk=pk)
                except SectionImage.DoesNotExist:
                    raise ValidationError(
                        'No file with ID %s available in this section' % pk)

                serializer_params['instance'] = file

            serializer = RootFileBase64Serializer(**serializer_params)
            serializer.is_valid(raise_exception=True)

            # save serializer in data so it can be used when handling the files
            file_data['serializer'] = serializer

        return data

    def _handle_images(self, section, data):
        new_image_ids = set()

        for image_data in data:
            serializer = image_data.pop('serializer')
            image = serializer.save(section=section)
            new_image_ids.add(image.id)

        for image in section.images.exclude(id__in=new_image_ids):
            image.soft_delete()

        return section

    def _handle_files(self, section, data):
        new_file_ids = set()

        for file_data in data:
            serializer = file_data.pop('serializer')
            file = serializer.save(section=section)
            new_file_ids.add(file.id)

        for file in section.files.exclude(id__in=new_file_ids):
            file.soft_delete()

        return section

    def _validate_question_update(self, poll_data, poll):
        poll_has_answers = poll.n_answers > 0
        if not poll_has_answers:
            return
        try:
            old_poll_data = SectionPollSerializer(poll).data
            assert compare_serialized(old_poll_data['text'], poll_data['text'])
            assert len(old_poll_data['options']) == len(poll_data['options'])
            for old_option, option in zip(old_poll_data['options'],
                                          poll_data['options']):
                assert compare_serialized(old_option['text'], option['text'])
        except AssertionError:
            raise ValidationError(
                'Poll with ID %s has answers - editing it is not allowed' %
                repr(poll.pk))

    def validate_questions(self, data):
        for index, poll_data in enumerate(data):
            pk = poll_data.get('id')
            poll_data['ordering'] = index + 1
            serializer_params = {'data': poll_data}
            if pk:
                try:
                    poll = self.instance.polls.get(pk=pk)
                except SectionPoll.DoesNotExist:
                    raise ValidationError(
                        'The Section does not have a poll with ID %s' %
                        repr(pk))
                self._validate_question_update(poll_data, poll)
                serializer_params['instance'] = poll
            serializer = SectionPollSerializer(**serializer_params)
            serializer.is_valid(raise_exception=True)
            # save serializer in data so it can be used when handling the polls
            poll_data['serializer'] = serializer
        return data

    def _handle_questions(self, section, data):
        new_poll_ids = set()
        for poll_data in data:
            serializer = poll_data.pop('serializer')
            poll = serializer.save(section=section,
                                   ordering=poll_data['ordering'])
            new_poll_ids.add(poll.id)
        for poll in section.polls.exclude(id__in=new_poll_ids):
            poll.soft_delete()

    def to_representation(self, instance):
        data = super().to_representation(instance)
        data['images'] = SectionImageSerializer(
            instance.images.all(),
            many=True,
            context=self.context,
        ).data
        data['questions'] = SectionPollSerializer(instance.polls.all(),
                                                  many=True).data
        return data