Skip to content
Snippets Groups Projects
serializers.py 18.4 KiB
Newer Older
  • Learn to ignore specific revisions
  • #
    # steering, Programme/schedule management for AURA
    #
    # Copyright (C) 2011-2017, 2020, Ernesto Rico Schmidt
    # Copyright (C) 2017-2019, Ingo Leindecker
    #
    # This program is free software: you can redistribute it and/or modify it under
    # the terms of the GNU Affero General Public License as published by the Free
    # Software Foundation, either version 3 of the License, or (at your option) any
    # later version.
    #
    # This program is distributed in the hope that it will be useful, but WITHOUT
    # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    # FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
    # details.
    #
    # You should have received a copy of the GNU Affero General Public License
    # along with this program.  If not, see <http://www.gnu.org/licenses/>.
    #
    
    
    from django.contrib.auth.models import User
    
    from django.core.exceptions import ObjectDoesNotExist
    
    from django.utils import timezone
    from rest_framework import serializers
    
    
    from profile.serializers import ProfileSerializer
    
    from program.models import (
        Show,
        Schedule,
        TimeSlot,
        Category,
        FundingCategory,
        Host,
        Topic,
        MusicFocus,
        Note,
        Type,
        Language,
        RRule,
        Link,
    )
    
    from steering.settings import THUMBNAIL_SIZES
    
    from program.utils import get_audio_url
    
    Ingo Leindecker's avatar
    Ingo Leindecker committed
    
    
    class UserSerializer(serializers.ModelSerializer):
        # Add profile fields to JSON
    
        profile = ProfileSerializer(required=False)
    
            fields = (
                "id",
                "username",
                "first_name",
                "last_name",
                "email",
                "is_staff",
                "is_active",
                "is_superuser",
                "password",
                "profile",
            )
    
    
        def create(self, validated_data):
            """
            Create and return a new User instance, given the validated data.
            """
    
    
            profile_data = (
                validated_data.pop("profile") if "profile" in validated_data else None
            )
    
            user = super(UserSerializer, self).create(validated_data)
    
            user.date_joined = timezone.now()
    
            user.set_password(validated_data["password"])
    
                profile = Profile(
                    user=user,
                    cba_username=profile_data.get("cba_username").strip(),
                    cba_user_token=profile_data.get("cba_user_token").strip(),
                )
    
    
        def update(self, instance, validated_data):
            """
            Update and return an existing User instance, given the validated data.
            """
    
    
            instance.first_name = validated_data.get("first_name", instance.first_name)
            instance.last_name = validated_data.get("last_name", instance.last_name)
            instance.email = validated_data.get("email", instance.email)
            instance.is_active = validated_data.get("is_active", instance.is_active)
            instance.is_staff = validated_data.get("is_staff", instance.is_staff)
            instance.is_superuser = validated_data.get(
                "is_superuser", instance.is_superuser
            )
    
            profile_data = (
                validated_data.pop("profile") if "profile" in validated_data else None
            )
    
            if profile_data:
                # TODO: How to hook into this from ProfileSerializer without having to call it here?
                try:
                    profile = Profile.objects.get(user=instance.id)
                except ObjectDoesNotExist:
                    profile = Profile.objects.create(user=instance, **profile_data)
    
    
                profile.cba_username = profile_data.get("cba_username")
                profile.cba_user_token = profile_data.get("cba_user_token")
    
    
            instance.save()
            return instance
    
    
    class CategorySerializer(serializers.ModelSerializer):
    
        # TODO: remove this when the dashboard is updated
    
        category = serializers.CharField(source="name")
    
            # TODO: replace `category` with `name` when the dashboard is updated
    
            fields = ("category", "abbrev", "slug", "is_active", "description")
    
    class LinkSerializer(serializers.ModelSerializer):
        class Meta:
            model = Link
    
            fields = ("description", "url")
    
    class HostSerializer(serializers.ModelSerializer):
    
        links = LinkSerializer(many=True, required=False)
    
    Ernesto Rico Schmidt's avatar
    Ernesto Rico Schmidt committed
        thumbnails = serializers.SerializerMethodField()  # Read-only
    
    Ingo Leindecker's avatar
    Ingo Leindecker committed
    
    
    Ernesto Rico Schmidt's avatar
    Ernesto Rico Schmidt committed
        @staticmethod
        def get_thumbnails(host):
    
    Ingo Leindecker's avatar
    Ingo Leindecker committed
            """Returns thumbnails"""
            thumbnails = []
    
            if host.image.name and THUMBNAIL_SIZES:
                for size in THUMBNAIL_SIZES:
                    thumbnails.append(host.image.crop[size].name)
    
            return thumbnails
    
    
            fields = "__all__"
    
            links_data = validated_data.pop("links", [])
    
            host = Host.objects.create(**validated_data)
    
            for link_data in links_data:
                Link.objects.create(host=host, **link_data)
            host.save()
            return host
    
    
        def update(self, instance, validated_data):
            """
            Update and return an existing Host instance, given the validated data.
            """
    
            instance.name = validated_data.get("name", instance.name)
            instance.is_active = validated_data.get("is_active", instance.is_active)
            instance.email = validated_data.get("email", instance.email)
            instance.website = validated_data.get("website", instance.website)
            instance.biography = validated_data.get("biography", instance.biography)
            instance.image = validated_data.get("image", instance.image)
            instance.ppoi = validated_data.get("ppoi", instance.ppoi)
    
            if instance.links.count() > 0:
                for link in instance.links.all():
                    link.delete(keep_parents=True)
    
            if links := validated_data.get("links"):
    
                for link_data in links:
                    Link.objects.create(host=instance, **link_data)
    
    
    class LanguageSerializer(serializers.ModelSerializer):
        class Meta:
            model = Language
    
            fields = ("name", "is_active")
    
    class TopicSerializer(serializers.ModelSerializer):
    
        # TODO: remove this when the dashboard is updated
    
        topic = serializers.CharField(source="name")
    
            # TODO: replace `topic` with `name` when the dashboard is updated
    
            fields = ("topic", "abbrev", "slug", "is_active")
    
    class MusicFocusSerializer(serializers.ModelSerializer):
    
        # TODO: remove this when the dashboard is updated
    
        focus = serializers.CharField(source="name")
    
            # TODO: replace `focus` with `name` when the dashboard is updated
    
            fields = ("focus", "abbrev", "slug", "is_active")
    
        # TODO: remove this when the dashboard is updated
    
        type = serializers.CharField(source="name")
    
            # TODO: replace `type` with `name` when the dashboard is updated
    
            fields = ("type", "slug", "is_active")
    
    class FundingCategorySerializer(serializers.ModelSerializer):
    
        # TODO: remove this when the dashboard is updated
    
        fundingcategory = serializers.CharField(source="name")
    
            model = FundingCategory
    
            # TODO: replace `fundingcategory` with `name` when the dashboard is updated
    
            fields = ("fundingcategory", "abbrev", "slug", "is_active")
    
    class ShowSerializer(serializers.HyperlinkedModelSerializer):
    
    Ernesto Rico Schmidt's avatar
    Ernesto Rico Schmidt committed
        owners = serializers.PrimaryKeyRelatedField(queryset=User.objects.all(), many=True)
    
        category = serializers.PrimaryKeyRelatedField(
            queryset=Category.objects.all(), many=True
        )
    
    Ernesto Rico Schmidt's avatar
    Ernesto Rico Schmidt committed
        hosts = serializers.PrimaryKeyRelatedField(queryset=Host.objects.all(), many=True)
    
        language = serializers.PrimaryKeyRelatedField(
            queryset=Language.objects.all(), many=True
        )
    
    Ernesto Rico Schmidt's avatar
    Ernesto Rico Schmidt committed
        topic = serializers.PrimaryKeyRelatedField(queryset=Topic.objects.all(), many=True)
    
        # TODO: replace `musicfocs` with `music_focus` and remove the source when the dashboard is
        #  updated
        musicfocus = serializers.PrimaryKeyRelatedField(
            queryset=MusicFocus.objects.all(), source="music_focus", many=True
        )
    
        type = serializers.PrimaryKeyRelatedField(queryset=Type.objects.all())
    
        # TODO: replace `fundingcategory` with `funding_category` and remove the source when the
        #  dashboard is updated
        fundingcategory = serializers.PrimaryKeyRelatedField(
            queryset=FundingCategory.objects.all(), source="funding_category"
        )
        predecessor = serializers.PrimaryKeyRelatedField(
            queryset=Show.objects.all(), required=False, allow_null=True
        )
    
    Ernesto Rico Schmidt's avatar
    Ernesto Rico Schmidt committed
        thumbnails = serializers.SerializerMethodField()  # Read-only
    
    Ingo Leindecker's avatar
    Ingo Leindecker committed
    
    
    Ernesto Rico Schmidt's avatar
    Ernesto Rico Schmidt committed
        @staticmethod
        def get_thumbnails(show):
    
    Ingo Leindecker's avatar
    Ingo Leindecker committed
            """Returns thumbnails"""
            thumbnails = []
    
            if show.image.name and THUMBNAIL_SIZES:
                for size in THUMBNAIL_SIZES:
                    thumbnails.append(show.image.crop[size].name)
    
            return thumbnails
    
    
            fields = (
                "id",
                "name",
                "slug",
                "image",
                "ppoi",
                "logo",
                "short_description",
                "description",
                "email",
                "website",
                "type",
                "fundingcategory",
                "predecessor",
                "cba_series_id",
                "default_playlist_id",
                "category",
                "hosts",
                "owners",
                "language",
                "topic",
                "musicfocus",
                "thumbnails",
                "is_active",
                "is_public",
            )
    
    
        def create(self, validated_data):
            """
            Create and return a new Show instance, given the validated data.
            """
    
            owners = validated_data.pop("owners")
            category = validated_data.pop("category")
            hosts = validated_data.pop("hosts")
            language = validated_data.pop("language")
            topic = validated_data.pop("topic")
            music_focus = validated_data.pop("music_focus")
    
    
            show = Show.objects.create(**validated_data)
    
            # Save many-to-many relationships
    
            show.owners.set(owners)
            show.category.set(category)
            show.hosts.set(hosts)
            show.language.set(language)
            show.topic.set(topic)
    
            show.music_focus.set(music_focus)
    
    
        def update(self, instance, validated_data):
            """
            Update and return an existing Show instance, given the validated data.
            """
    
    
            instance.name = validated_data.get("name", instance.name)
            instance.slug = validated_data.get("slug", instance.slug)
            instance.image = validated_data.get("image", instance.image)
            instance.ppoi = validated_data.get("ppoi", instance.ppoi)
            instance.logo = validated_data.get("logo", instance.logo)
            instance.short_description = validated_data.get(
                "short_description", instance.short_description
            )
            instance.description = validated_data.get("description", instance.description)
            instance.email = validated_data.get("email", instance.email)
            instance.website = validated_data.get("website", instance.website)
            instance.cba_series_id = validated_data.get(
                "cba_series_id", instance.cba_series_id
            )
            instance.default_playlist_id = validated_data.get(
                "default_playlist_id", instance.default_playlist_id
            )
            instance.type = validated_data.get("type", instance.type)
            instance.funding_category = validated_data.get(
                "funding_category", instance.funding_category
            )
            instance.predecessor = validated_data.get("predecessor", instance.predecessor)
            instance.is_active = validated_data.get("is_active", instance.is_active)
            instance.is_public = validated_data.get("is_public", instance.is_public)
    
            instance.owners.set(validated_data.get("owners", instance.owners))
            instance.category.set(validated_data.get("category", instance.category))
            instance.hosts.set(validated_data.get("hosts", instance.hosts))
            instance.language.set(validated_data.get("language", instance.language))
            instance.topic.set(validated_data.get("topic", instance.topic))
            instance.music_focus.set(
                validated_data.get("music_focus", instance.music_focus)
            )
    
    class ScheduleSerializer(serializers.ModelSerializer):
    
        rrule = serializers.PrimaryKeyRelatedField(queryset=RRule.objects.all())
        show = serializers.PrimaryKeyRelatedField(queryset=Show.objects.all())
    
        # TODO: remove this when the dashboard is updated
    
        byweekday = serializers.IntegerField(source="by_weekday")
        dstart = serializers.DateField(source="first_date")
        tstart = serializers.TimeField(source="start_time")
        tend = serializers.TimeField(source="end_time")
        until = serializers.DateField(source="last_date")
    
        class Meta:
            model = Schedule
    
            fields = "__all__"
    
    
        def create(self, validated_data):
    
            """Create and return a new Schedule instance, given the validated data."""
    
    
            rrule = validated_data.pop("rrule")
            show = validated_data.pop("show")
    
    
            schedule = Schedule.objects.create(**validated_data)
            schedule.rrule = rrule
            schedule.show = show
    
            schedule.save()
            return schedule
    
    
        def update(self, instance, validated_data):
    
            """Update and return an existing Schedule instance, given the validated data."""
    
    
            instance.by_weekday = validated_data.get("byweekday", instance.by_weekday)
            instance.first_date = validated_data.get("dstart", instance.first_date)
            instance.start_time = validated_data.get("tstart", instance.start_time)
            instance.end_time = validated_data.get("tend", instance.end_time)
            instance.last_date = validated_data.get("until", instance.last_date)
            instance.is_repetition = validated_data.get(
                "is_repetition", instance.is_repetition
            )
            instance.default_playlist_id = validated_data.get(
                "default_playlist_id", instance.default_playlist_id
            )
            instance.rrule = validated_data.get("rrule", instance.rrule)
            instance.show = validated_data.get("show", instance.show)
            instance.add_days_no = validated_data.get("add_days_no", instance.add_days_no)
            instance.add_business_days_only = validated_data.get(
                "add_business_days_only", instance.add_business_days_only
            )
    
    class TimeSlotSerializer(serializers.ModelSerializer):
    
        show = serializers.PrimaryKeyRelatedField(queryset=Show.objects.all())
        schedule = serializers.PrimaryKeyRelatedField(queryset=Schedule.objects.all())
    
    
            fields = "__all__"
    
            """Create and return a new TimeSlot instance, given the validated data."""
    
            return TimeSlot.objects.create(**validated_data)
    
        def update(self, instance, validated_data):
    
            """Update and return an existing Show instance, given the validated data."""
    
            # Only save certain fields
    
            instance.memo = validated_data.get("memo", instance.memo)
            instance.is_repetition = validated_data.get(
                "is_repetition", instance.is_repetition
            )
            instance.playlist_id = validated_data.get("playlist_id", instance.playlist_id)
    
            instance.save()
            return instance
    
    
    class NoteSerializer(serializers.ModelSerializer):
    
        show = serializers.PrimaryKeyRelatedField(queryset=Show.objects.all())
        timeslot = serializers.PrimaryKeyRelatedField(queryset=TimeSlot.objects.all())
    
        host = serializers.PrimaryKeyRelatedField(queryset=Host.objects.all())
    
    Ernesto Rico Schmidt's avatar
    Ernesto Rico Schmidt committed
        thumbnails = serializers.SerializerMethodField()  # Read-only
    
    Ingo Leindecker's avatar
    Ingo Leindecker committed
    
    
    Ernesto Rico Schmidt's avatar
    Ernesto Rico Schmidt committed
        @staticmethod
        def get_thumbnails(note):
    
    Ingo Leindecker's avatar
    Ingo Leindecker committed
            """Returns thumbnails"""
            thumbnails = []
    
            if note.image.name and THUMBNAIL_SIZES:
                for size in THUMBNAIL_SIZES:
                    thumbnails.append(note.image.crop[size].name)
    
            return thumbnails
    
    
            fields = "__all__"
    
            """Create and return a new Note instance, given the validated data."""
    
            # Save the creator
    
            validated_data["user_id"] = self.context["user_id"]
    
    
            # Try to retrieve audio URL from CBA
    
            validated_data["audio_url"] = get_audio_url(validated_data["cba_id"])
    
            note = Note.objects.create(**validated_data)
    
            # Assign note to timeslot
    
    Ernesto Rico Schmidt's avatar
    Ernesto Rico Schmidt committed
            if note.timeslot_id is not None:
    
                try:
                    timeslot = TimeSlot.objects.get(pk=note.timeslot_id)
                    timeslot.note_id = note.id
                    timeslot.save(update_fields=["note_id"])
                except ObjectDoesNotExist:
                    pass
    
            return note
    
    
        def update(self, instance, validated_data):
    
            """Update and return an existing Note instance, given the validated data."""
    
            instance.show = validated_data.get("show", instance.show)
            instance.timeslot = validated_data.get("timeslot", instance.timeslot)
            instance.title = validated_data.get("title", instance.title)
            instance.slug = validated_data.get("slug", instance.slug)
            instance.summary = validated_data.get("summary", instance.summary)
            instance.content = validated_data.get("content", instance.content)
            instance.image = validated_data.get("image", instance.image)
            instance.ppoi = validated_data.get("ppoi", instance.ppoi)
            instance.status = validated_data.get("status", instance.status)
            instance.host = validated_data.get("host", instance.host)
            instance.cba_id = validated_data.get("cba_id", instance.cba_id)
    
            instance.audio_url = get_audio_url(instance.cba_id)
    
    
            # Remove existing note connections from timeslots
            timeslots = TimeSlot.objects.filter(note_id=instance.id)
            for ts in timeslots:
                ts.note_id = None
                ts.save(update_fields=["note_id"])
    
            # Assign note to timeslot
    
    Ernesto Rico Schmidt's avatar
    Ernesto Rico Schmidt committed
            if instance.timeslot.id is not None:
    
                try:
                    timeslot = TimeSlot.objects.get(pk=instance.timeslot.id)
                    timeslot.note_id = instance.id
                    timeslot.save(update_fields=["note_id"])
                except ObjectDoesNotExist:
                    pass