Skip to content
Snippets Groups Projects
serializers.py 42.5 KiB
Newer Older
  • Learn to ignore specific revisions
  • class NoteLinkSerializer(serializers.ModelSerializer):
    
        type_id = serializers.PrimaryKeyRelatedField(queryset=LinkType.objects.all(), source="type")
    
    
            fields = ("type_id", "url")
    
    tags_json_schema = {"type": "array", "items": {"type": "string"}}
    
    class NoteSerializer(serializers.ModelSerializer):
    
        contributor_ids = serializers.PrimaryKeyRelatedField(
    
            queryset=Profile.objects.all(),
    
            required=False,
            source="contributors",
    
            help_text="`Profile` IDs that contributed to this episode.",
    
        image_id = serializers.PrimaryKeyRelatedField(
    
            queryset=Image.objects.all(),
            required=False,
            allow_null=True,
            source="image",
            help_text="`Image` ID.",
    
        language_ids = serializers.PrimaryKeyRelatedField(
            allow_null=True,
            many=True,
            queryset=Language.objects.all(),
            required=False,
            source="language",
    
            help_text="Array of `Language` IDs.",
    
        links = NoteLinkSerializer(many=True, required=False, help_text="Array of `Link` objects.")
        playlist_id = serializers.IntegerField(required=False, help_text="Array of `Playlist` IDs.")
        tags = JSONSchemaField(tags_json_schema, required=False, help_text="Tags of the Note.")
    
        timeslot_id = serializers.PrimaryKeyRelatedField(
    
            queryset=TimeSlot.objects.all(),
            required=False,
            source="timeslot",
            help_text="`Timeslot` ID.",
    
        topic_ids = serializers.PrimaryKeyRelatedField(
    
            allow_null=True,
            many=True,
            queryset=Topic.objects.all(),
            required=False,
            source="topic",
            help_text="Array of `Topic`IDs.",
    
    Ingo Leindecker's avatar
    Ingo Leindecker committed
    
    
            read_only_fields = (
    
                "created_at",
                "created_by",
                "updated_at",
                "updated_by",
            )
    
    Ernesto Rico Schmidt's avatar
    Ernesto Rico Schmidt committed
                "cba_id",
                "content",
    
    Ernesto Rico Schmidt's avatar
    Ernesto Rico Schmidt committed
                "links",
    
    Ernesto Rico Schmidt's avatar
    Ernesto Rico Schmidt committed
                "title",
    
            ) + read_only_fields
    
            """Create and return a new Note instance, given the validated data."""
    
            links_data = validated_data.pop("links", [])
    
            show = validated_data["timeslot"].schedule.show
    
            user = self.context.get("request").user
            user_is_owner = user in show.owners.all()
    
    
            # Having the create_note permission overrides the ownership
    
            if not (
                user.has_perm("program.create_note")
                or (user.has_perm("program.add_note") and user_is_owner)
            ):
    
                raise exceptions.PermissionDenied(detail="You are not allowed to create this note.")
    
            # we derive `contributors`, `language` and `topic` from the Show's values if not set
    
            contributors = validated_data.pop("contributors", show.hosts.values_list("id", flat=True))
    
            language = validated_data.pop("language", show.language.values_list("id", flat=True))
            topic = validated_data.pop("topic", show.topic.values_list("id", flat=True))
    
            # optional foreign key
    
            validated_data["image"] = validated_data.pop("image", None)
    
            try:
                note = Note.objects.create(
                    created_by=self.context.get("request").user.username,
                    **validated_data,
                )
            except IntegrityError:
                raise exceptions.ValidationError(
                    code="duplicate", detail="note for this timeslot already exists."
                )
            else:
                note.contributors.set(contributors)
                note.language.set(language)
                note.topic.set(topic)
    
                # optional nested objects
                for link_data in links_data:
                    NoteLink.objects.create(note=note, **link_data)
    
    
        def update(self, instance, validated_data):
    
            """Update and return an existing Note instance, given the validated data."""
    
    
            user = self.context.get("request").user
    
            user_is_owner = user in instance.timeslot.schedule.show.owners.all()
    
            # Having the update_note permission overrides the ownership
    
            if not (
                user.has_perm("program.update_note")
                or (user.has_perm("program.change_note") and user_is_owner)
            ):
    
                raise exceptions.PermissionDenied(detail="You are not allowed to update this note.")
    
            if "cba_id" in validated_data:
                instance.cba_id = validated_data.get("cba_id")
    
            if "content" in validated_data:
                instance.content = validated_data.get("content")
    
            if "image" in validated_data:
                instance.image = validated_data.get("image")
    
            if "summary" in validated_data:
                instance.summary = validated_data.get("summary")
    
            if "timeslot" in validated_data:
                instance.timeslot = validated_data.get("timeslot")
    
            if "tags" in validated_data:
                instance.tags = validated_data.get("tags")
    
            if "title" in validated_data:
                instance.title = validated_data.get("title")
    
            if "contributors" in validated_data:
                instance.contributors.set(validated_data.get("contributors", []))
    
            if "language" in validated_data:
                instance.language.set(validated_data.get("language", []))
    
            # Only update this field if the user has the update_note permission, ignore otherwise
            if "topic" in validated_data and user.has_perm("program.update_note"):
    
                instance.topic.set(validated_data.get("topic", []))
    
            # optional nested objects
    
            if "links" in validated_data:
    
                instance = update_links(instance, validated_data.get("links"))
    
            instance.updated_by = self.context.get("request").user.username
    
    
    
    class RadioSettingsSerializer(serializers.ModelSerializer):
        cba = serializers.SerializerMethodField()
    
        image_requirements = serializers.SerializerMethodField()
    
        playout = serializers.SerializerMethodField()
    
        program = serializers.SerializerMethodField()
    
        station = serializers.SerializerMethodField()
    
        class Meta:
    
            fields = read_only_fields = (
                "id",
                "cba",
                "image_requirements",
                "playout",
    
            model = RadioSettings
    
    
        def get_cba(self, obj) -> RadioCBASettings:
    
            if self.context.get("request").user.is_authenticated:
    
                return RadioCBASettings(
                    api_key=obj.cba_api_key,
                    domains=obj.cba_domains,
                )
    
                return RadioCBASettings(domains=obj.cba_domains)
    
        @staticmethod
        def get_image_requirements(obj) -> RadioImageRequirementsSettings:
    
            def get_aspect_ratio(field) -> tuple[int, int] | tuple[float, float]:
                """return the tuple of ints or floats representing the aspect ratio of the image."""
    
                try:
                    return int(values[0]), int(values[1])
                except ValueError:
                    return float(values[0]), float(values[1])
    
                "note.image": get_aspect_ratio(obj.note_image_aspect_ratio),
    
                "profile.image": get_aspect_ratio(obj.profile_image_aspect_ratio),
    
                "show.image": get_aspect_ratio(obj.show_image_aspect_ratio),
                "show.logo": get_aspect_ratio(obj.show_logo_aspect_ratio),
    
                        "aspect_ratio": aspect_ratios["note.image"],
                        "shape": obj.profile_image_shape,
    
                        "aspect_ratio": aspect_ratios["profile.image"],
                        "shape": obj.profile_image_shape,
    
                    }
                },
                "show.image": {
                    "frame": {
                        "aspect_ratio": aspect_ratios["show.image"],
    
                        "shape": obj.profile_image_shape,
    
                    }
                },
                "show.logo": {
                    "frame": {
                        "aspect_ratio": aspect_ratios["show.logo"],
    
                        "shape": obj.profile_image_shape,
    
        @staticmethod
    
        def get_program(obj) -> RadioProgramSettings:
    
            return RadioProgramSettings(
                micro=MicroProgram(show_id=obj.micro_show.id if obj.micro_show else None),
                fallback=ProgramFallback(
                    show_id=obj.fallback_show.id if obj.fallback_show else None,
                    default_pool="fallback" if obj.fallback_default_pool else "",
                ),
            )
    
        def get_playout(obj) -> RadioPlayoutSettings:
    
            return RadioPlayoutSettings(
                line_in_channels=obj.line_in_channels,
                pools=obj.pools,
            )
    
        def get_station(obj) -> RadioStationSettings:
    
            logo = (
                Logo(
                    url=f"{settings.SITE_URL}{obj.station_logo.url}",
                    height=obj.station_logo.height,
                    width=obj.station_logo.width,
                )
                if obj.station_logo
                else None
            )
    
            return RadioStationSettings(
                name=obj.station_name,
                logo=logo,
                website=obj.station_website,
            )
    
    # done this way to get the schema annotations for datetime right
    class NestedTimeslotSerializer(serializers.Serializer):
    
        end = serializers.DateTimeField()
    
        id = serializers.IntegerField(allow_null=True)
    
        is_virtual = serializers.BooleanField()
    
        memo = serializers.CharField()
        playlist_id = serializers.IntegerField(allow_null=True)
        repetition_of_id = serializers.IntegerField(allow_null=True)
    
        start = serializers.DateTimeField()
    
    
    
    class PlayoutEntrySerializer(serializers.Serializer):
        episode = serializers.SerializerMethodField()
    
        schedule = serializers.SerializerMethodField(allow_null=True)
    
        show = serializers.SerializerMethodField()
        timeslot = NestedTimeslotSerializer()
    
        @staticmethod
        def get_episode(obj) -> NestedEpisode:
            pass
    
        @staticmethod
        def get_schedule(obj) -> NestedSchedule:
            pass
    
        @staticmethod
        def get_show(obj) -> NestedShow:
            pass
    
    class ProgramEntrySerializer(serializers.Serializer):
        episode = serializers.SerializerMethodField()
        show = serializers.SerializerMethodField()
        timeslot = NestedTimeslotSerializer()
    
        @staticmethod
        def get_episode(obj) -> NestedEpisode:
            pass
    
        @staticmethod
        def get_schedule(obj) -> NestedSchedule:
            pass
    
        @staticmethod
        def get_show(obj) -> NestedShow:
            pass