class ImportMetadataSerializer(serializers.Serializer): title = serializers.CharField(max_length=500, required=True) description = serializers.CharField( max_length=5000, required=False, allow_null=True ) mbid = serializers.UUIDField(required=False, allow_null=True) copyright = serializers.CharField(max_length=500, required=False, allow_null=True) position = serializers.IntegerField(min_value=1, required=False, allow_null=True) tags = tags_serializers.TagsListField(required=False) license = common_serializers.RelatedField( "code", LicenseSerializer(), required=False, allow_null=True ) cover = common_serializers.RelatedField( "uuid", queryset=common_models.Attachment.objects.all().local(), serializer=None, queryset_filter=lambda qs, context: qs.filter(actor=context["actor"]), write_only=True, required=False, allow_null=True, ) album = common_serializers.RelatedField( "id", queryset=models.Album.objects.all(), serializer=None, queryset_filter=filter_album, write_only=True, required=False, allow_null=True, )
class TagMutation(mutations.UpdateMutationSerializer): tags = tags_serializers.TagsListField() def get_previous_state_handlers(self): handlers = super().get_previous_state_handlers() handlers["tags"] = lambda obj: list( sorted(obj.tagged_items.values_list("tag__name", flat=True))) return handlers def update(self, instance, validated_data): tags = validated_data.pop("tags", NOOP) r = super().update(instance, validated_data) if tags != NOOP: tags_models.set_tags(instance, *tags) return r
class AlbumCreateSerializer(serializers.Serializer): title = serializers.CharField(required=True, max_length=255) cover = COVER_WRITE_FIELD release_date = serializers.DateField(required=False, allow_null=True) tags = tags_serializers.TagsListField(required=False) description = common_serializers.ContentSerializer(allow_null=True, required=False) artist = common_serializers.RelatedField( "id", queryset=models.Artist.objects.exclude(channel__isnull=True), required=True, serializer=None, filters=lambda context: {"attributed_to": context["user"].actor}, ) def validate(self, validated_data): duplicates = validated_data["artist"].albums.filter( title__iexact=validated_data["title"] ) if duplicates.exists(): raise serializers.ValidationError("An album with this title already exist") return super().validate(validated_data) def to_representation(self, obj): obj.artist.attachment_cover return AlbumSerializer(obj, context=self.context).data def create(self, validated_data): instance = models.Album.objects.create( attributed_to=self.context["user"].actor, artist=validated_data["artist"], release_date=validated_data.get("release_date"), title=validated_data["title"], attachment_cover=validated_data.get("cover"), ) common_utils.attach_content( instance, "description", validated_data.get("description") ) tag_models.set_tags(instance, *(validated_data.get("tags", []) or [])) instance.artist.get_channel() return instance
class ChannelCreateSerializer(serializers.Serializer): name = serializers.CharField(max_length=music_models.MAX_LENGTHS["ARTIST_NAME"]) username = serializers.CharField( max_length=music_models.MAX_LENGTHS["ARTIST_NAME"], validators=[users_serializers.ASCIIUsernameValidator()], ) description = common_serializers.ContentSerializer(allow_null=True) tags = tags_serializers.TagsListField() content_category = serializers.ChoiceField( choices=music_models.ARTIST_CONTENT_CATEGORY_CHOICES ) metadata = serializers.DictField(required=False) cover = music_serializers.COVER_WRITE_FIELD def validate(self, validated_data): existing_channels = self.context["actor"].owned_channels.count() if existing_channels >= preferences.get("audio__max_channels"): raise serializers.ValidationError( "You have reached the maximum amount of allowed channels" ) validated_data = super().validate(validated_data) metadata = validated_data.pop("metadata", {}) if validated_data["content_category"] == "podcast": metadata_serializer = ChannelMetadataSerializer(data=metadata) metadata_serializer.is_valid(raise_exception=True) metadata = metadata_serializer.validated_data validated_data["metadata"] = metadata return validated_data def validate_username(self, value): if value.lower() in [n.lower() for n in settings.ACCOUNT_USERNAME_BLACKLIST]: raise serializers.ValidationError("This username is already taken") matching = federation_models.Actor.objects.local().filter( preferred_username__iexact=value ) if matching.exists(): raise serializers.ValidationError("This username is already taken") return value @transaction.atomic def create(self, validated_data): from . import views cover = validated_data.pop("cover", None) description = validated_data.get("description") artist = music_models.Artist.objects.create( attributed_to=validated_data["attributed_to"], name=validated_data["name"], content_category=validated_data["content_category"], attachment_cover=cover, ) common_utils.attach_content(artist, "description", description) if validated_data.get("tags", []): tags_models.set_tags(artist, *validated_data["tags"]) channel = models.Channel( artist=artist, attributed_to=validated_data["attributed_to"], metadata=validated_data["metadata"], ) channel.actor = models.generate_actor( validated_data["username"], name=validated_data["name"], ) channel.library = music_models.Library.objects.create( name=channel.actor.preferred_username, privacy_level="everyone", actor=validated_data["attributed_to"], ) channel.save() channel = views.ChannelViewSet.queryset.get(pk=channel.pk) return channel def to_representation(self, obj): return ChannelSerializer(obj, context=self.context).data
class ChannelUpdateSerializer(serializers.Serializer): name = serializers.CharField(max_length=music_models.MAX_LENGTHS["ARTIST_NAME"]) description = common_serializers.ContentSerializer(allow_null=True) tags = tags_serializers.TagsListField() content_category = serializers.ChoiceField( choices=music_models.ARTIST_CONTENT_CATEGORY_CHOICES ) metadata = serializers.DictField(required=False) cover = music_serializers.COVER_WRITE_FIELD def validate(self, validated_data): validated_data = super().validate(validated_data) require_metadata_validation = False new_content_category = validated_data.get("content_category") metadata = validated_data.pop("metadata", NOOP) if ( new_content_category == "podcast" and self.instance.artist.content_category != "postcast" ): # updating channel, setting as podcast require_metadata_validation = True elif self.instance.artist.content_category == "postcast" and metadata != NOOP: # channel is podcast, and metadata was updated require_metadata_validation = True else: metadata = self.instance.metadata if require_metadata_validation: metadata_serializer = ChannelMetadataSerializer(data=metadata) metadata_serializer.is_valid(raise_exception=True) metadata = metadata_serializer.validated_data validated_data["metadata"] = metadata return validated_data @transaction.atomic def update(self, obj, validated_data): if validated_data.get("tags") is not None: tags_models.set_tags(obj.artist, *validated_data["tags"]) actor_update_fields = [] artist_update_fields = [] obj.metadata = validated_data["metadata"] obj.save(update_fields=["metadata"]) if "description" in validated_data: common_utils.attach_content( obj.artist, "description", validated_data["description"] ) if "name" in validated_data: actor_update_fields.append(("name", validated_data["name"])) artist_update_fields.append(("name", validated_data["name"])) if "content_category" in validated_data: artist_update_fields.append( ("content_category", validated_data["content_category"]) ) if "cover" in validated_data: artist_update_fields.append(("attachment_cover", validated_data["cover"])) if actor_update_fields: for field, value in actor_update_fields: setattr(obj.actor, field, value) obj.actor.save(update_fields=[f for f, _ in actor_update_fields]) if artist_update_fields: for field, value in artist_update_fields: setattr(obj.artist, field, value) obj.artist.save(update_fields=[f for f, _ in artist_update_fields]) return obj def to_representation(self, obj): return ChannelSerializer(obj, context=self.context).data
def test_tags_list_field_honor_TAGS_MAX_BY_OBJ(max, tags, expected, settings): settings.TAGS_MAX_BY_OBJ = max field = serializers.TagsListField() assert field.to_internal_value(tags) == expected