From a865fcdcf118540ac86d2b1042beb76598e07dea Mon Sep 17 00:00:00 2001
From: Eliot Berriot
Date: Tue, 2 Oct 2018 19:30:13 +0200
Subject: [PATCH] Fix #551: Added a library widget to display libraries
associated with a track, album and artist
---
api/funkwhale_api/music/views.py | 40 ++++++++-
api/tests/music/test_views.py | 31 +++++++
changes/changelog.d/551.enhancement | 1 +
front/src/components/common/CopyInput.vue | 7 +-
.../components/federation/LibraryWidget.vue | 84 +++++++++++++++++++
front/src/components/library/Album.vue | 12 ++-
front/src/components/library/Artist.vue | 12 ++-
front/src/components/library/Track.vue | 12 ++-
front/src/views/content/remote/Card.vue | 21 ++++-
9 files changed, 210 insertions(+), 10 deletions(-)
create mode 100644 changes/changelog.d/551.enhancement
create mode 100644 front/src/components/federation/LibraryWidget.vue
diff --git a/api/funkwhale_api/music/views.py b/api/funkwhale_api/music/views.py
index 5c92ad2b1..871dfc920 100644
--- a/api/funkwhale_api/music/views.py
+++ b/api/funkwhale_api/music/views.py
@@ -3,7 +3,7 @@ import urllib
from django.conf import settings
from django.db import transaction
-from django.db.models import Count, Prefetch, Sum, F
+from django.db.models import Count, Prefetch, Sum, F, Q
from django.db.models.functions import Length
from django.utils import timezone
@@ -26,6 +26,28 @@ from . import filters, models, serializers, tasks, utils
logger = logging.getLogger(__name__)
+def get_libraries(filter_uploads):
+ def view(self, request, *args, **kwargs):
+ obj = self.get_object()
+ actor = utils.get_actor_from_request(request)
+ uploads = models.Upload.objects.all()
+ uploads = filter_uploads(obj, uploads)
+ uploads = uploads.playable_by(actor)
+ libraries = models.Library.objects.filter(
+ pk__in=uploads.values_list("library", flat=True)
+ )
+ libraries = libraries.select_related("actor")
+ page = self.paginate_queryset(libraries)
+ if page is not None:
+ serializer = federation_api_serializers.LibrarySerializer(page, many=True)
+ return self.get_paginated_response(serializer.data)
+
+ serializer = federation_api_serializers.LibrarySerializer(libraries, many=True)
+ return Response(serializer.data)
+
+ return view
+
+
class TagViewSetMixin(object):
def get_queryset(self):
queryset = super().get_queryset()
@@ -50,6 +72,14 @@ class ArtistViewSet(viewsets.ReadOnlyModelViewSet):
)
return queryset.prefetch_related(Prefetch("albums", queryset=albums)).distinct()
+ libraries = detail_route(methods=["get"])(
+ get_libraries(
+ filter_uploads=lambda o, uploads: uploads.filter(
+ Q(track__artist=o) | Q(track__album__artist=o)
+ )
+ )
+ )
+
class AlbumViewSet(viewsets.ReadOnlyModelViewSet):
queryset = (
@@ -76,6 +106,10 @@ class AlbumViewSet(viewsets.ReadOnlyModelViewSet):
qs = queryset.prefetch_related(Prefetch("tracks", queryset=tracks))
return qs.distinct()
+ libraries = detail_route(methods=["get"])(
+ get_libraries(filter_uploads=lambda o, uploads: uploads.filter(track__album=o))
+ )
+
class LibraryViewSet(
mixins.CreateModelMixin,
@@ -197,6 +231,10 @@ class TrackViewSet(TagViewSetMixin, viewsets.ReadOnlyModelViewSet):
serializer = serializers.LyricsSerializer(lyrics)
return Response(serializer.data)
+ libraries = detail_route(methods=["get"])(
+ get_libraries(filter_uploads=lambda o, uploads: uploads.filter(track=o))
+ )
+
def get_file_path(audio_file):
serve_path = settings.MUSIC_DIRECTORY_SERVE_PATH
diff --git a/api/tests/music/test_views.py b/api/tests/music/test_views.py
index 691fa049e..2f9d66e5b 100644
--- a/api/tests/music/test_views.py
+++ b/api/tests/music/test_views.py
@@ -449,3 +449,34 @@ def test_user_can_list_own_library_follows(factories, logged_in_api_client):
"previous": None,
"results": [federation_api_serializers.LibraryFollowSerializer(follow).data],
}
+
+
+@pytest.mark.parametrize("entity", ["artist", "album", "track"])
+def test_can_get_libraries_for_music_entities(
+ factories, api_client, entity, preferences
+):
+ preferences["common__api_authentication_required"] = False
+ upload = factories["music.Upload"](playable=True)
+ # another private library that should not appear
+ factories["music.Upload"](
+ import_status="finished", library__privacy_level="me", track=upload.track
+ ).library
+ library = upload.library
+ data = {
+ "artist": upload.track.artist,
+ "album": upload.track.album,
+ "track": upload.track,
+ }
+
+ url = reverse("api:v1:{}s-libraries".format(entity), kwargs={"pk": data[entity].pk})
+
+ response = api_client.get(url)
+ expected = federation_api_serializers.LibrarySerializer(library).data
+
+ assert response.status_code == 200
+ assert response.data == {
+ "count": 1,
+ "next": None,
+ "previous": None,
+ "results": [expected],
+ }
diff --git a/changes/changelog.d/551.enhancement b/changes/changelog.d/551.enhancement
new file mode 100644
index 000000000..267dba9f7
--- /dev/null
+++ b/changes/changelog.d/551.enhancement
@@ -0,0 +1 @@
+Added a library widget to display libraries associated with a track, album and artist (#551)
diff --git a/front/src/components/common/CopyInput.vue b/front/src/components/common/CopyInput.vue
index c2db315bd..af82f2c66 100644
--- a/front/src/components/common/CopyInput.vue
+++ b/front/src/components/common/CopyInput.vue
@@ -4,7 +4,7 @@
Text copied to clipboard!
-