From cfc88847a6903d9ad21d4cfcfe4f26005e03a952 Mon Sep 17 00:00:00 2001 From: Eliot Berriot Date: Wed, 15 Jan 2020 13:43:25 +0100 Subject: [PATCH] See #170: use new content obj for channel description --- api/funkwhale_api/audio/serializers.py | 26 ++++++++++++++++++-------- api/funkwhale_api/audio/views.py | 2 +- api/funkwhale_api/common/models.py | 6 ++++++ api/funkwhale_api/common/utils.py | 1 + api/funkwhale_api/music/serializers.py | 10 +++++++++- api/tests/audio/test_serializers.py | 26 +++++++++++++++++++++----- api/tests/audio/test_views.py | 12 ++++++------ 7 files changed, 62 insertions(+), 21 deletions(-) diff --git a/api/funkwhale_api/audio/serializers.py b/api/funkwhale_api/audio/serializers.py index dc3c11484..6b7bc00ef 100644 --- a/api/funkwhale_api/audio/serializers.py +++ b/api/funkwhale_api/audio/serializers.py @@ -2,6 +2,8 @@ from django.db import transaction from rest_framework import serializers +from funkwhale_api.common import serializers as common_serializers +from funkwhale_api.common import utils as common_utils from funkwhale_api.federation import serializers as federation_serializers from funkwhale_api.music import models as music_models from funkwhale_api.music import serializers as music_serializers @@ -14,25 +16,28 @@ from . import models 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"]) - summary = serializers.CharField(max_length=500, allow_blank=True, allow_null=True) + description = common_serializers.ContentSerializer(allow_null=True) tags = tags_serializers.TagsListField() @transaction.atomic def create(self, validated_data): + description = validated_data.get("description") artist = music_models.Artist.objects.create( attributed_to=validated_data["attributed_to"], name=validated_data["name"] ) + description_obj = 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"] ) - + summary = description_obj.rendered if description_obj else None channel.actor = models.generate_actor( - validated_data["username"], - summary=validated_data["summary"], - name=validated_data["name"], + validated_data["username"], summary=summary, name=validated_data["name"], ) channel.library = music_models.Library.objects.create( @@ -49,7 +54,7 @@ class ChannelCreateSerializer(serializers.Serializer): class ChannelUpdateSerializer(serializers.Serializer): name = serializers.CharField(max_length=music_models.MAX_LENGTHS["ARTIST_NAME"]) - summary = serializers.CharField(max_length=500, allow_blank=True, allow_null=True) + description = common_serializers.ContentSerializer(allow_null=True) tags = tags_serializers.TagsListField() @transaction.atomic @@ -58,8 +63,13 @@ class ChannelUpdateSerializer(serializers.Serializer): tags_models.set_tags(obj.artist, *validated_data["tags"]) actor_update_fields = [] - if "summary" in validated_data: - actor_update_fields.append(("summary", validated_data["summary"])) + if "description" in validated_data: + description_obj = common_utils.attach_content( + obj.artist, "description", validated_data["description"] + ) + if description_obj: + actor_update_fields.append(("summary", description_obj.rendered)) + if "name" in validated_data: obj.artist.name = validated_data["name"] obj.artist.save(update_fields=["name"]) diff --git a/api/funkwhale_api/audio/views.py b/api/funkwhale_api/audio/views.py index 856c6b050..9e77d043b 100644 --- a/api/funkwhale_api/audio/views.py +++ b/api/funkwhale_api/audio/views.py @@ -30,7 +30,7 @@ class ChannelViewSet( serializer_class = serializers.ChannelSerializer queryset = ( models.Channel.objects.all() - .prefetch_related("library", "attributed_to", "artist", "actor") + .prefetch_related("library", "attributed_to", "artist__description", "actor") .order_by("-creation_date") ) permission_classes = [ diff --git a/api/funkwhale_api/common/models.py b/api/funkwhale_api/common/models.py index 8750d5d7a..993b1cef1 100644 --- a/api/funkwhale_api/common/models.py +++ b/api/funkwhale_api/common/models.py @@ -289,6 +289,12 @@ class Content(models.Model): text = models.CharField(max_length=CONTENT_TEXT_MAX_LENGTH, blank=True, null=True) content_type = models.CharField(max_length=100) + @property + def rendered(self): + from . import utils + + return utils.render_html(self.text, self.content_type) + @receiver(models.signals.post_save, sender=Attachment) def warm_attachment_thumbnails(sender, instance, **kwargs): diff --git a/api/funkwhale_api/common/utils.py b/api/funkwhale_api/common/utils.py index f3f3cc0f1..9b230f411 100644 --- a/api/funkwhale_api/common/utils.py +++ b/api/funkwhale_api/common/utils.py @@ -305,3 +305,4 @@ def attach_content(obj, field, content_data): ) setattr(obj, field, content_obj) obj.save(update_fields=[field]) + return content_obj diff --git a/api/funkwhale_api/music/serializers.py b/api/funkwhale_api/music/serializers.py index 1049b3d9f..dcaeaadd0 100644 --- a/api/funkwhale_api/music/serializers.py +++ b/api/funkwhale_api/music/serializers.py @@ -134,7 +134,7 @@ class ArtistWithAlbumsSerializer(OptionalDescriptionMixin, serializers.Serialize def serialize_artist_simple(artist): - return { + data = { "id": artist.id, "fid": artist.fid, "mbid": str(artist.mbid), @@ -142,6 +142,14 @@ def serialize_artist_simple(artist): "creation_date": DATETIME_FIELD.to_representation(artist.creation_date), "is_local": artist.is_local, } + if "description" in artist._state.fields_cache: + data["description"] = ( + common_serializers.ContentSerializer(artist.description).data + if artist.description + else None + ) + + return data def serialize_album_track(track): diff --git a/api/tests/audio/test_serializers.py b/api/tests/audio/test_serializers.py index a9f3948fb..61beda82a 100644 --- a/api/tests/audio/test_serializers.py +++ b/api/tests/audio/test_serializers.py @@ -1,4 +1,6 @@ from funkwhale_api.audio import serializers +from funkwhale_api.common import serializers as common_serializers +from funkwhale_api.common import utils as common_utils from funkwhale_api.federation import serializers as federation_serializers from funkwhale_api.music import serializers as music_serializers @@ -10,7 +12,7 @@ def test_channel_serializer_create(factories): # TODO: cover "name": "My channel", "username": "mychannel", - "summary": "This is my channel", + "description": {"text": "This is my channel", "content_type": "text/markdown"}, "tags": ["hello", "world"], } @@ -25,8 +27,14 @@ def test_channel_serializer_create(factories): sorted(channel.artist.tagged_items.values_list("tag__name", flat=True)) == data["tags"] ) + assert channel.artist.description.text == data["description"]["text"] + assert ( + channel.artist.description.content_type == data["description"]["content_type"] + ) assert channel.attributed_to == attributed_to - assert channel.actor.summary == data["summary"] + assert channel.actor.summary == common_utils.render_html( + data["description"]["text"], "text/markdown" + ) assert channel.actor.preferred_username == data["username"] assert channel.actor.name == data["name"] assert channel.library.privacy_level == "everyone" @@ -39,7 +47,7 @@ def test_channel_serializer_update(factories): data = { # TODO: cover "name": "My channel", - "summary": "This is my channel", + "description": {"text": "This is my channel", "content_type": "text/markdown"}, "tags": ["hello", "world"], } @@ -54,12 +62,17 @@ def test_channel_serializer_update(factories): sorted(channel.artist.tagged_items.values_list("tag__name", flat=True)) == data["tags"] ) - assert channel.actor.summary == data["summary"] + assert channel.actor.summary == common_utils.render_html( + data["description"]["text"], "text/markdown" + ) + assert channel.artist.description.text == data["description"]["text"] + assert channel.artist.description.content_type == "text/markdown" assert channel.actor.name == data["name"] def test_channel_serializer_representation(factories, to_api_date): - channel = factories["audio.Channel"]() + content = factories["common.Content"]() + channel = factories["audio.Channel"](artist__description=content) expected = { "artist": music_serializers.serialize_artist_simple(channel.artist), @@ -70,5 +83,8 @@ def test_channel_serializer_representation(factories, to_api_date): channel.attributed_to ).data, } + expected["artist"]["description"] = common_serializers.ContentSerializer( + content + ).data assert serializers.ChannelSerializer(channel).data == expected diff --git a/api/tests/audio/test_views.py b/api/tests/audio/test_views.py index 074046d0a..1ef650989 100644 --- a/api/tests/audio/test_views.py +++ b/api/tests/audio/test_views.py @@ -12,16 +12,16 @@ def test_channel_create(logged_in_api_client): # TODO: cover "name": "My channel", "username": "mychannel", - "summary": "This is my channel", + "description": {"text": "This is my channel", "content_type": "text/markdown"}, "tags": ["hello", "world"], } url = reverse("api:v1:channels-list") - response = logged_in_api_client.post(url, data) + response = logged_in_api_client.post(url, data, format="json") assert response.status_code == 201 - channel = actor.owned_channels.latest("id") + channel = actor.owned_channels.select_related("artist__description").latest("id") expected = serializers.ChannelSerializer(channel).data assert response.data == expected @@ -32,14 +32,14 @@ def test_channel_create(logged_in_api_client): == data["tags"] ) assert channel.attributed_to == actor - assert channel.actor.summary == data["summary"] + assert channel.actor.summary == channel.artist.description.rendered assert channel.actor.preferred_username == data["username"] assert channel.library.privacy_level == "everyone" assert channel.library.actor == actor def test_channel_detail(factories, logged_in_api_client): - channel = factories["audio.Channel"]() + channel = factories["audio.Channel"](artist__description=None) url = reverse("api:v1:channels-detail", kwargs={"uuid": channel.uuid}) expected = serializers.ChannelSerializer(channel).data response = logged_in_api_client.get(url) @@ -49,7 +49,7 @@ def test_channel_detail(factories, logged_in_api_client): def test_channel_list(factories, logged_in_api_client): - channel = factories["audio.Channel"]() + channel = factories["audio.Channel"](artist__description=None) url = reverse("api:v1:channels-list") expected = serializers.ChannelSerializer(channel).data response = logged_in_api_client.get(url)