From ec3fcefabff66a0874ec226260a46192dd287825 Mon Sep 17 00:00:00 2001 From: Eliot Berriot Date: Fri, 28 Sep 2018 22:19:43 +0200 Subject: [PATCH] Ensure radio tracks only return playable tracks --- api/funkwhale_api/federation/admin.py | 2 +- api/funkwhale_api/federation/api_views.py | 4 +-- api/funkwhale_api/music/models.py | 6 ++-- api/funkwhale_api/radios/radios.py | 2 ++ api/tests/radios/test_radios.py | 44 ++++++++++++----------- 5 files changed, 32 insertions(+), 26 deletions(-) diff --git a/api/funkwhale_api/federation/admin.py b/api/funkwhale_api/federation/admin.py index 5128781e8..7be8ac89c 100644 --- a/api/funkwhale_api/federation/admin.py +++ b/api/funkwhale_api/federation/admin.py @@ -15,7 +15,7 @@ redeliver_deliveries.short_description = "Redeliver" def redeliver_activities(modeladmin, request, queryset): for activity in queryset.select_related("actor__user"): - if activity.actor.is_local: + if activity.actor.get_user(): tasks.dispatch_outbox.delay(activity_id=activity.pk) else: tasks.dispatch_inbox.delay(activity_id=activity.pk) diff --git a/api/funkwhale_api/federation/api_views.py b/api/funkwhale_api/federation/api_views.py index 1f33ce859..75ffad0b2 100644 --- a/api/funkwhale_api/federation/api_views.py +++ b/api/funkwhale_api/federation/api_views.py @@ -94,7 +94,7 @@ class LibraryViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet): queryset = ( music_models.Library.objects.all() .order_by("-creation_date") - .select_related("actor") + .select_related("actor__user") .annotate(_uploads_count=Count("uploads")) ) serializer_class = api_serializers.LibrarySerializer @@ -107,7 +107,7 @@ class LibraryViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet): @decorators.detail_route(methods=["post"]) def scan(self, request, *args, **kwargs): library = self.get_object() - if library.actor.is_local: + if library.actor.get_user(): return response.Response({"status": "skipped"}, 200) scan = library.schedule_scan(actor=request.user.actor) diff --git a/api/funkwhale_api/music/models.py b/api/funkwhale_api/music/models.py index 5395dd5e9..4d72d10f7 100644 --- a/api/funkwhale_api/music/models.py +++ b/api/funkwhale_api/music/models.py @@ -576,7 +576,7 @@ TRACK_FILE_IMPORT_STATUS_CHOICES = ( def get_file_path(instance, filename): - if instance.library.actor.is_local: + if instance.library.actor.get_user(): return common_utils.ChunkedPath("tracks")(instance, filename) else: # we cache remote tracks in a different directory @@ -725,7 +725,7 @@ class Upload(models.Model): self.mimetype = mimetypes.guess_type(self.source)[0] if not self.size and self.audio_file: self.size = self.audio_file.size - if not self.pk and not self.fid and self.library.actor.is_local: + if not self.pk and not self.fid and self.library.actor.get_user(): self.fid = self.get_federation_id() return super().save(**kwargs) @@ -908,7 +908,7 @@ class Library(federation_models.FederationMixin): def should_autoapprove_follow(self, actor): if self.privacy_level == "everyone": return True - if self.privacy_level == "instance" and actor.is_local: + if self.privacy_level == "instance" and actor.get_user(): return True return False diff --git a/api/funkwhale_api/radios/radios.py b/api/funkwhale_api/radios/radios.py index 7b3aca4cf..8d9eb816a 100644 --- a/api/funkwhale_api/radios/radios.py +++ b/api/funkwhale_api/radios/radios.py @@ -54,6 +54,8 @@ class SessionRadio(SimpleRadio): queryset = self.get_queryset(**kwargs) if self.session: queryset = self.filter_from_session(queryset) + if kwargs.pop("filter_playable", True): + queryset = queryset.playable_by(self.session.user.actor) return queryset def filter_from_session(self, queryset): diff --git a/api/tests/radios/test_radios.py b/api/tests/radios/test_radios.py index 7fa00eea2..7e8f260d0 100644 --- a/api/tests/radios/test_radios.py +++ b/api/tests/radios/test_radios.py @@ -76,7 +76,7 @@ def test_can_get_choices_for_custom_radio(factories): session = factories["radios.CustomRadioSession"]( custom_radio__config=[{"type": "artist", "ids": [artist.pk]}] ) - choices = session.radio.get_choices() + choices = session.radio.get_choices(filter_playable=False) expected = [t.pk for t in tracks] assert list(choices.values_list("id", flat=True)) == expected @@ -94,19 +94,19 @@ def test_cannot_start_custom_radio_if_not_owner_or_not_public(factories): assert message in serializer.errors["non_field_errors"] -def test_can_start_custom_radio_from_api(logged_in_client, factories): +def test_can_start_custom_radio_from_api(logged_in_api_client, factories): artist = factories["music.Artist"]() radio = factories["radios.Radio"]( - config=[{"type": "artist", "ids": [artist.pk]}], user=logged_in_client.user + config=[{"type": "artist", "ids": [artist.pk]}], user=logged_in_api_client.user ) url = reverse("api:v1:radios:sessions-list") - response = logged_in_client.post( + response = logged_in_api_client.post( url, {"radio_type": "custom", "custom_radio": radio.pk} ) assert response.status_code == 201 session = radio.sessions.latest("id") assert session.radio_type == "custom" - assert session.user == logged_in_client.user + assert session.user == logged_in_api_client.user def test_can_use_radio_session_to_filter_choices(factories): @@ -116,7 +116,7 @@ def test_can_use_radio_session_to_filter_choices(factories): session = radio.start_session(user) for i in range(10): - radio.pick() + radio.pick(filter_playable=False) # ensure 10 differents tracks have been suggested tracks_id = [ @@ -134,30 +134,34 @@ def test_can_restore_radio_from_previous_session(factories): assert radio.session == restarted_radio.session -def test_can_start_radio_for_logged_in_user(logged_in_client): +def test_can_start_radio_for_logged_in_user(logged_in_api_client): url = reverse("api:v1:radios:sessions-list") - logged_in_client.post(url, {"radio_type": "random"}) + logged_in_api_client.post(url, {"radio_type": "random"}) session = models.RadioSession.objects.latest("id") assert session.radio_type == "random" - assert session.user == logged_in_client.user + assert session.user == logged_in_api_client.user -def test_can_get_track_for_session_from_api(factories, logged_in_client): - files = factories["music.Upload"].create_batch(1) - tracks = [f.track for f in files] +def test_can_get_track_for_session_from_api(factories, logged_in_api_client): + actor = logged_in_api_client.user.create_actor() + track = factories["music.Upload"]( + library__actor=actor, import_status="finished" + ).track url = reverse("api:v1:radios:sessions-list") - response = logged_in_client.post(url, {"radio_type": "random"}) + response = logged_in_api_client.post(url, {"radio_type": "random"}) session = models.RadioSession.objects.latest("id") url = reverse("api:v1:radios:tracks-list") - response = logged_in_client.post(url, {"session": session.pk}) + response = logged_in_api_client.post(url, {"session": session.pk}) data = json.loads(response.content.decode("utf-8")) - assert data["track"]["id"] == tracks[0].id + assert data["track"]["id"] == track.pk assert data["position"] == 1 - next_track = factories["music.Upload"]().track - response = logged_in_client.post(url, {"session": session.pk}) + next_track = factories["music.Upload"]( + library__actor=actor, import_status="finished" + ).track + response = logged_in_api_client.post(url, {"session": session.pk}) data = json.loads(response.content.decode("utf-8")) assert data["track"]["id"] == next_track.id @@ -188,7 +192,7 @@ def test_can_start_artist_radio(factories): session = radio.start_session(user, related_object=artist) assert session.radio_type == "artist" for i in range(5): - assert radio.pick() in good_tracks + assert radio.pick(filter_playable=False) in good_tracks def test_can_start_tag_radio(factories): @@ -202,7 +206,7 @@ def test_can_start_tag_radio(factories): session = radio.start_session(user, related_object=tag) assert session.radio_type == "tag" for i in range(5): - assert radio.pick() in good_tracks + assert radio.pick(filter_playable=False) in good_tracks def test_can_start_artist_radio_from_api(logged_in_api_client, preferences, factories): @@ -232,4 +236,4 @@ def test_can_start_less_listened_radio(factories): radio.start_session(user) for i in range(5): - assert radio.pick() in good_tracks + assert radio.pick(filter_playable=False) in good_tracks