diff --git a/api/funkwhale_api/common/serializers.py b/api/funkwhale_api/common/serializers.py index 03817424e..4461a1c5e 100644 --- a/api/funkwhale_api/common/serializers.py +++ b/api/funkwhale_api/common/serializers.py @@ -293,7 +293,17 @@ class AttachmentSerializer(serializers.Serializer): file = StripExifImageField(write_only=True) urls = serializers.SerializerMethodField() - @extend_schema_field(OpenApiTypes.OBJECT) + @extend_schema_field( + { + "type": "object", + "properties": { + "original": {"type": "string"}, + "small_square_crop": {"type": "string"}, + "medium_square_crop": {"type": "string"}, + "large_square_crop": {"type": "string"}, + }, + } + ) def get_urls(self, o): urls = {} urls["source"] = o.url diff --git a/api/funkwhale_api/music/serializers.py b/api/funkwhale_api/music/serializers.py index ed61d9ec1..c01585759 100644 --- a/api/funkwhale_api/music/serializers.py +++ b/api/funkwhale_api/music/serializers.py @@ -140,10 +140,11 @@ class ArtistWithAlbumsSerializer(OptionalDescriptionMixin, serializers.Serialize return getattr(o, "_tracks_count", 0) -class SimpleArtistSerializer(serializers.ModelSerializer): +class ArtistSerializer(serializers.ModelSerializer): cover = CoverField(allow_null=True, required=False) description = common_serializers.ContentSerializer(allow_null=True, required=False) channel = serializers.UUIDField(allow_null=True, required=False) + tags = serializers.SerializerMethodField() class Meta: model = models.Artist @@ -160,59 +161,21 @@ class SimpleArtistSerializer(serializers.ModelSerializer): "cover", "channel", "attributed_to", + "tags", ) - -class ArtistCreditSerializer(serializers.ModelSerializer): - artist = SimpleArtistSerializer() - - class Meta: - model = models.ArtistCredit - fields = ["artist", "credit", "joinphrase", "index"] - - -class AlbumSerializer(OptionalDescriptionMixin, serializers.Serializer): - artist_credit = ArtistCreditSerializer(many=True) - description = common_serializers.ContentSerializer(allow_null=True, required=False) - cover = CoverField(allow_null=True) - is_playable = serializers.SerializerMethodField() - tags = serializers.SerializerMethodField() - tracks_count = serializers.SerializerMethodField() - attributed_to = APIActorSerializer() - id = serializers.IntegerField() - fid = serializers.URLField() - mbid = serializers.UUIDField() - title = serializers.CharField() - release_date = serializers.DateField() - creation_date = serializers.DateTimeField() - is_local = serializers.BooleanField() - duration = serializers.SerializerMethodField(read_only=True) - - def get_tracks_count(self, o) -> int: - return len(o.tracks.all()) - - def get_is_playable(self, obj) -> bool: - try: - return any( - [ - bool(getattr(t, "is_playable_by_actor", None)) - for t in obj.tracks.all() - ] - ) - except AttributeError: - return None - @extend_schema_field({"type": "array", "items": {"type": "string"}}) def get_tags(self, obj): tagged_items = getattr(obj, "_prefetched_tagged_items", []) return [ti.tag.name for ti in tagged_items] - def get_duration(self, obj) -> int: - try: - return obj.duration - except AttributeError: - # no annotation? - return 0 + +class ArtistCreditSerializer(serializers.ModelSerializer): + artist = ArtistSerializer() + + class Meta: + model = models.ArtistCredit + fields = ["artist", "credit", "joinphrase", "index"] class TrackAlbumSerializer(serializers.ModelSerializer): @@ -318,6 +281,51 @@ class TrackSerializer(OptionalDescriptionMixin, serializers.Serializer): return bool(getattr(obj, "playable_uploads", [])) +class AlbumSerializer(OptionalDescriptionMixin, serializers.Serializer): + artist_credit = ArtistCreditSerializer(many=True) + cover = CoverField(allow_null=True) + is_playable = serializers.SerializerMethodField() + tags = serializers.SerializerMethodField() + tracks_count = serializers.SerializerMethodField() + attributed_to = APIActorSerializer() + id = serializers.IntegerField() + fid = serializers.URLField() + mbid = serializers.UUIDField() + title = serializers.CharField() + release_date = serializers.DateField() + creation_date = serializers.DateTimeField() + is_local = serializers.BooleanField() + duration = serializers.SerializerMethodField(read_only=True) + tracks = TrackSerializer(many=True, allow_null=True) + description = common_serializers.ContentSerializer(allow_null=True, required=False) + + def get_tracks_count(self, o) -> int: + return len(o.tracks.all()) + + def get_is_playable(self, obj) -> bool: + try: + return any( + [ + bool(getattr(t, "is_playable_by_actor", None)) + for t in obj.tracks.all() + ] + ) + except AttributeError: + return None + + @extend_schema_field({"type": "array", "items": {"type": "string"}}) + def get_tags(self, obj): + tagged_items = getattr(obj, "_prefetched_tagged_items", []) + return [ti.tag.name for ti in tagged_items] + + def get_duration(self, obj) -> int: + try: + return obj.duration + except AttributeError: + # no annotation? + return 0 + + @common_serializers.track_fields_for_update("name", "description", "privacy_level") class LibraryForOwnerSerializer(serializers.ModelSerializer): uploads_count = serializers.SerializerMethodField() diff --git a/api/funkwhale_api/playlists/views.py b/api/funkwhale_api/playlists/views.py index a5e6f653a..98872f601 100644 --- a/api/funkwhale_api/playlists/views.py +++ b/api/funkwhale_api/playlists/views.py @@ -256,5 +256,5 @@ class PlaylistViewSet( except models.PlaylistTrack.DoesNotExist: return Response(status=404) artists = music_models.Artist.objects.filter(pk__in=artists_pks) - serializer = music_serializers.SimpleArtistSerializer(artists, many=True) + serializer = music_serializers.ArtistSerializer(artists, many=True) return Response(serializer.data, status=200) diff --git a/api/tests/music/test_serializers.py b/api/tests/music/test_serializers.py index 9dd5a67de..c0c7fc100 100644 --- a/api/tests/music/test_serializers.py +++ b/api/tests/music/test_serializers.py @@ -199,6 +199,9 @@ def test_album_serializer(factories, to_api_date): "tags": [], "attributed_to": federation_serializers.APIActorSerializer(actor).data, "description": None, + "tracks": [ + serializers.TrackSerializer(track).data for track in album.tracks.all() + ], } serializer = serializers.AlbumSerializer( album.__class__.objects.with_tracks_count().get(pk=album.pk) @@ -232,6 +235,9 @@ def test_track_album_serializer(factories, to_api_date): "tags": [], "attributed_to": federation_serializers.APIActorSerializer(actor).data, "description": None, + "tracks": [ + serializers.TrackSerializer(track).data for track in album.tracks.all() + ], } serializer = serializers.AlbumSerializer( album.__class__.objects.with_tracks_count().get(pk=album.pk) diff --git a/changes/changelog.d/2404.bugfix b/changes/changelog.d/2404.bugfix new file mode 100644 index 000000000..d187891b4 --- /dev/null +++ b/changes/changelog.d/2404.bugfix @@ -0,0 +1 @@ +Fix schema generation to allow propre types in front (#2404)