See #170: use new content obj for channel description
This commit is contained in:
parent
e6f8b6e406
commit
cfc88847a6
|
@ -2,6 +2,8 @@ from django.db import transaction
|
||||||
|
|
||||||
from rest_framework import serializers
|
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.federation import serializers as federation_serializers
|
||||||
from funkwhale_api.music import models as music_models
|
from funkwhale_api.music import models as music_models
|
||||||
from funkwhale_api.music import serializers as music_serializers
|
from funkwhale_api.music import serializers as music_serializers
|
||||||
|
@ -14,25 +16,28 @@ from . import models
|
||||||
class ChannelCreateSerializer(serializers.Serializer):
|
class ChannelCreateSerializer(serializers.Serializer):
|
||||||
name = serializers.CharField(max_length=music_models.MAX_LENGTHS["ARTIST_NAME"])
|
name = serializers.CharField(max_length=music_models.MAX_LENGTHS["ARTIST_NAME"])
|
||||||
username = 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()
|
tags = tags_serializers.TagsListField()
|
||||||
|
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
def create(self, validated_data):
|
def create(self, validated_data):
|
||||||
|
description = validated_data.get("description")
|
||||||
artist = music_models.Artist.objects.create(
|
artist = music_models.Artist.objects.create(
|
||||||
attributed_to=validated_data["attributed_to"], name=validated_data["name"]
|
attributed_to=validated_data["attributed_to"], name=validated_data["name"]
|
||||||
)
|
)
|
||||||
|
description_obj = common_utils.attach_content(
|
||||||
|
artist, "description", description
|
||||||
|
)
|
||||||
|
|
||||||
if validated_data.get("tags", []):
|
if validated_data.get("tags", []):
|
||||||
tags_models.set_tags(artist, *validated_data["tags"])
|
tags_models.set_tags(artist, *validated_data["tags"])
|
||||||
|
|
||||||
channel = models.Channel(
|
channel = models.Channel(
|
||||||
artist=artist, attributed_to=validated_data["attributed_to"]
|
artist=artist, attributed_to=validated_data["attributed_to"]
|
||||||
)
|
)
|
||||||
|
summary = description_obj.rendered if description_obj else None
|
||||||
channel.actor = models.generate_actor(
|
channel.actor = models.generate_actor(
|
||||||
validated_data["username"],
|
validated_data["username"], summary=summary, name=validated_data["name"],
|
||||||
summary=validated_data["summary"],
|
|
||||||
name=validated_data["name"],
|
|
||||||
)
|
)
|
||||||
|
|
||||||
channel.library = music_models.Library.objects.create(
|
channel.library = music_models.Library.objects.create(
|
||||||
|
@ -49,7 +54,7 @@ class ChannelCreateSerializer(serializers.Serializer):
|
||||||
|
|
||||||
class ChannelUpdateSerializer(serializers.Serializer):
|
class ChannelUpdateSerializer(serializers.Serializer):
|
||||||
name = serializers.CharField(max_length=music_models.MAX_LENGTHS["ARTIST_NAME"])
|
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()
|
tags = tags_serializers.TagsListField()
|
||||||
|
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
|
@ -58,8 +63,13 @@ class ChannelUpdateSerializer(serializers.Serializer):
|
||||||
tags_models.set_tags(obj.artist, *validated_data["tags"])
|
tags_models.set_tags(obj.artist, *validated_data["tags"])
|
||||||
actor_update_fields = []
|
actor_update_fields = []
|
||||||
|
|
||||||
if "summary" in validated_data:
|
if "description" in validated_data:
|
||||||
actor_update_fields.append(("summary", validated_data["summary"]))
|
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:
|
if "name" in validated_data:
|
||||||
obj.artist.name = validated_data["name"]
|
obj.artist.name = validated_data["name"]
|
||||||
obj.artist.save(update_fields=["name"])
|
obj.artist.save(update_fields=["name"])
|
||||||
|
|
|
@ -30,7 +30,7 @@ class ChannelViewSet(
|
||||||
serializer_class = serializers.ChannelSerializer
|
serializer_class = serializers.ChannelSerializer
|
||||||
queryset = (
|
queryset = (
|
||||||
models.Channel.objects.all()
|
models.Channel.objects.all()
|
||||||
.prefetch_related("library", "attributed_to", "artist", "actor")
|
.prefetch_related("library", "attributed_to", "artist__description", "actor")
|
||||||
.order_by("-creation_date")
|
.order_by("-creation_date")
|
||||||
)
|
)
|
||||||
permission_classes = [
|
permission_classes = [
|
||||||
|
|
|
@ -289,6 +289,12 @@ class Content(models.Model):
|
||||||
text = models.CharField(max_length=CONTENT_TEXT_MAX_LENGTH, blank=True, null=True)
|
text = models.CharField(max_length=CONTENT_TEXT_MAX_LENGTH, blank=True, null=True)
|
||||||
content_type = models.CharField(max_length=100)
|
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)
|
@receiver(models.signals.post_save, sender=Attachment)
|
||||||
def warm_attachment_thumbnails(sender, instance, **kwargs):
|
def warm_attachment_thumbnails(sender, instance, **kwargs):
|
||||||
|
|
|
@ -305,3 +305,4 @@ def attach_content(obj, field, content_data):
|
||||||
)
|
)
|
||||||
setattr(obj, field, content_obj)
|
setattr(obj, field, content_obj)
|
||||||
obj.save(update_fields=[field])
|
obj.save(update_fields=[field])
|
||||||
|
return content_obj
|
||||||
|
|
|
@ -134,7 +134,7 @@ class ArtistWithAlbumsSerializer(OptionalDescriptionMixin, serializers.Serialize
|
||||||
|
|
||||||
|
|
||||||
def serialize_artist_simple(artist):
|
def serialize_artist_simple(artist):
|
||||||
return {
|
data = {
|
||||||
"id": artist.id,
|
"id": artist.id,
|
||||||
"fid": artist.fid,
|
"fid": artist.fid,
|
||||||
"mbid": str(artist.mbid),
|
"mbid": str(artist.mbid),
|
||||||
|
@ -142,6 +142,14 @@ def serialize_artist_simple(artist):
|
||||||
"creation_date": DATETIME_FIELD.to_representation(artist.creation_date),
|
"creation_date": DATETIME_FIELD.to_representation(artist.creation_date),
|
||||||
"is_local": artist.is_local,
|
"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):
|
def serialize_album_track(track):
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
from funkwhale_api.audio import serializers
|
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.federation import serializers as federation_serializers
|
||||||
from funkwhale_api.music import serializers as music_serializers
|
from funkwhale_api.music import serializers as music_serializers
|
||||||
|
|
||||||
|
@ -10,7 +12,7 @@ def test_channel_serializer_create(factories):
|
||||||
# TODO: cover
|
# TODO: cover
|
||||||
"name": "My channel",
|
"name": "My channel",
|
||||||
"username": "mychannel",
|
"username": "mychannel",
|
||||||
"summary": "This is my channel",
|
"description": {"text": "This is my channel", "content_type": "text/markdown"},
|
||||||
"tags": ["hello", "world"],
|
"tags": ["hello", "world"],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,8 +27,14 @@ def test_channel_serializer_create(factories):
|
||||||
sorted(channel.artist.tagged_items.values_list("tag__name", flat=True))
|
sorted(channel.artist.tagged_items.values_list("tag__name", flat=True))
|
||||||
== data["tags"]
|
== 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.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.preferred_username == data["username"]
|
||||||
assert channel.actor.name == data["name"]
|
assert channel.actor.name == data["name"]
|
||||||
assert channel.library.privacy_level == "everyone"
|
assert channel.library.privacy_level == "everyone"
|
||||||
|
@ -39,7 +47,7 @@ def test_channel_serializer_update(factories):
|
||||||
data = {
|
data = {
|
||||||
# TODO: cover
|
# TODO: cover
|
||||||
"name": "My channel",
|
"name": "My channel",
|
||||||
"summary": "This is my channel",
|
"description": {"text": "This is my channel", "content_type": "text/markdown"},
|
||||||
"tags": ["hello", "world"],
|
"tags": ["hello", "world"],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,12 +62,17 @@ def test_channel_serializer_update(factories):
|
||||||
sorted(channel.artist.tagged_items.values_list("tag__name", flat=True))
|
sorted(channel.artist.tagged_items.values_list("tag__name", flat=True))
|
||||||
== data["tags"]
|
== 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"]
|
assert channel.actor.name == data["name"]
|
||||||
|
|
||||||
|
|
||||||
def test_channel_serializer_representation(factories, to_api_date):
|
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 = {
|
expected = {
|
||||||
"artist": music_serializers.serialize_artist_simple(channel.artist),
|
"artist": music_serializers.serialize_artist_simple(channel.artist),
|
||||||
|
@ -70,5 +83,8 @@ def test_channel_serializer_representation(factories, to_api_date):
|
||||||
channel.attributed_to
|
channel.attributed_to
|
||||||
).data,
|
).data,
|
||||||
}
|
}
|
||||||
|
expected["artist"]["description"] = common_serializers.ContentSerializer(
|
||||||
|
content
|
||||||
|
).data
|
||||||
|
|
||||||
assert serializers.ChannelSerializer(channel).data == expected
|
assert serializers.ChannelSerializer(channel).data == expected
|
||||||
|
|
|
@ -12,16 +12,16 @@ def test_channel_create(logged_in_api_client):
|
||||||
# TODO: cover
|
# TODO: cover
|
||||||
"name": "My channel",
|
"name": "My channel",
|
||||||
"username": "mychannel",
|
"username": "mychannel",
|
||||||
"summary": "This is my channel",
|
"description": {"text": "This is my channel", "content_type": "text/markdown"},
|
||||||
"tags": ["hello", "world"],
|
"tags": ["hello", "world"],
|
||||||
}
|
}
|
||||||
|
|
||||||
url = reverse("api:v1:channels-list")
|
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
|
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
|
expected = serializers.ChannelSerializer(channel).data
|
||||||
|
|
||||||
assert response.data == expected
|
assert response.data == expected
|
||||||
|
@ -32,14 +32,14 @@ def test_channel_create(logged_in_api_client):
|
||||||
== data["tags"]
|
== data["tags"]
|
||||||
)
|
)
|
||||||
assert channel.attributed_to == actor
|
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.actor.preferred_username == data["username"]
|
||||||
assert channel.library.privacy_level == "everyone"
|
assert channel.library.privacy_level == "everyone"
|
||||||
assert channel.library.actor == actor
|
assert channel.library.actor == actor
|
||||||
|
|
||||||
|
|
||||||
def test_channel_detail(factories, logged_in_api_client):
|
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})
|
url = reverse("api:v1:channels-detail", kwargs={"uuid": channel.uuid})
|
||||||
expected = serializers.ChannelSerializer(channel).data
|
expected = serializers.ChannelSerializer(channel).data
|
||||||
response = logged_in_api_client.get(url)
|
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):
|
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")
|
url = reverse("api:v1:channels-list")
|
||||||
expected = serializers.ChannelSerializer(channel).data
|
expected = serializers.ChannelSerializer(channel).data
|
||||||
response = logged_in_api_client.get(url)
|
response = logged_in_api_client.get(url)
|
||||||
|
|
Loading…
Reference in New Issue