From 6d84a814d98c33136e472c819d1550916b5d82f5 Mon Sep 17 00:00:00 2001
From: Eliot Berriot <contact@eliotberriot.com>
Date: Tue, 15 Oct 2019 15:46:48 +0200
Subject: [PATCH] Revert "Apply suggestion to
 api/funkwhale_api/common/filters.py"

This reverts commit 4972d760e2809122af54060252be14a638cc87cc.
---
 api/funkwhale_api/common/filters.py    | 34 ++++++++++++++++++
 api/funkwhale_api/favorites/filters.py |  4 ++-
 api/funkwhale_api/history/filters.py   |  4 ++-
 api/funkwhale_api/music/filters.py     | 19 ++++++++--
 api/funkwhale_api/playlists/filters.py |  3 ++
 api/funkwhale_api/radios/filtersets.py |  8 ++++-
 api/tests/common/test_filters.py       | 50 ++++++++++++++++++++++++++
 7 files changed, 117 insertions(+), 5 deletions(-)

diff --git a/api/funkwhale_api/common/filters.py b/api/funkwhale_api/common/filters.py
index feca948bb..953904bfa 100644
--- a/api/funkwhale_api/common/filters.py
+++ b/api/funkwhale_api/common/filters.py
@@ -168,3 +168,37 @@ class MutationFilter(filters.FilterSet):
     class Meta:
         model = models.Mutation
         fields = ["is_approved", "is_applied", "type"]
+
+
+class ActorScopeFilter(filters.CharFilter):
+    def __init__(self, *args, **kwargs):
+        self.actor_field = kwargs.pop("actor_field")
+        super().__init__(*args, **kwargs)
+
+    def filter(self, queryset, value):
+        if not value:
+            return queryset
+
+        request = getattr(self.parent, "request", None)
+        if not request:
+            return queryset.none()
+
+        user = getattr(request, "user", None)
+        qs = queryset
+        if value.lower() == "me":
+            qs = self.filter_me(user=user, queryset=queryset)
+        elif value.lower() == "all":
+            return queryset
+        else:
+            return queryset.none()
+
+        if self.distinct:
+            qs = qs.distinct()
+        return qs
+
+    def filter_me(self, user, queryset):
+        actor = getattr(user, "actor", None)
+        if not actor:
+            return queryset.none()
+
+        return queryset.filter(**{self.actor_field: actor})
diff --git a/api/funkwhale_api/favorites/filters.py b/api/funkwhale_api/favorites/filters.py
index cf8048b8d..8a4b91bb2 100644
--- a/api/funkwhale_api/favorites/filters.py
+++ b/api/funkwhale_api/favorites/filters.py
@@ -1,4 +1,5 @@
 from funkwhale_api.common import fields
+from funkwhale_api.common import filters as common_filters
 from funkwhale_api.moderation import filters as moderation_filters
 
 from . import models
@@ -8,10 +9,11 @@ class TrackFavoriteFilter(moderation_filters.HiddenContentFilterSet):
     q = fields.SearchFilter(
         search_fields=["track__title", "track__artist__name", "track__album__title"]
     )
+    scope = common_filters.ActorScopeFilter(actor_field="user__actor", distinct=True)
 
     class Meta:
         model = models.TrackFavorite
-        fields = ["user", "q"]
+        fields = ["user", "q", "scope"]
         hidden_content_fields_mapping = moderation_filters.USER_FILTER_CONFIG[
             "TRACK_FAVORITE"
         ]
diff --git a/api/funkwhale_api/history/filters.py b/api/funkwhale_api/history/filters.py
index 02549b3b1..16a03204f 100644
--- a/api/funkwhale_api/history/filters.py
+++ b/api/funkwhale_api/history/filters.py
@@ -1,5 +1,6 @@
 import django_filters
 
+from funkwhale_api.common import filters as common_filters
 from funkwhale_api.moderation import filters as moderation_filters
 
 from . import models
@@ -8,10 +9,11 @@ from . import models
 class ListeningFilter(moderation_filters.HiddenContentFilterSet):
     username = django_filters.CharFilter("user__username")
     domain = django_filters.CharFilter("user__actor__domain_id")
+    scope = common_filters.ActorScopeFilter(actor_field="user__actor", distinct=True)
 
     class Meta:
         model = models.Listening
         hidden_content_fields_mapping = moderation_filters.USER_FILTER_CONFIG[
             "LISTENING"
         ]
-        fields = ["hidden"]
+        fields = ["hidden", "scope"]
diff --git a/api/funkwhale_api/music/filters.py b/api/funkwhale_api/music/filters.py
index 44763b966..f5bd17e67 100644
--- a/api/funkwhale_api/music/filters.py
+++ b/api/funkwhale_api/music/filters.py
@@ -23,12 +23,17 @@ class ArtistFilter(moderation_filters.HiddenContentFilterSet):
     q = fields.SearchFilter(search_fields=["name"])
     playable = filters.BooleanFilter(field_name="_", method="filter_playable")
     tag = TAG_FILTER
+    scope = common_filters.ActorScopeFilter(
+        actor_field="tracks__uploads__library__actor", distinct=True
+    )
 
     class Meta:
         model = models.Artist
         fields = {
             "name": ["exact", "iexact", "startswith", "icontains"],
-            "playable": "exact",
+            "playable": ["exact"],
+            "scope": ["exact"],
+            "mbid": ["exact"],
         }
         hidden_content_fields_mapping = moderation_filters.USER_FILTER_CONFIG["ARTIST"]
 
@@ -42,6 +47,9 @@ class TrackFilter(moderation_filters.HiddenContentFilterSet):
     playable = filters.BooleanFilter(field_name="_", method="filter_playable")
     tag = TAG_FILTER
     id = common_filters.MultipleQueryFilter(coerce=int)
+    scope = common_filters.ActorScopeFilter(
+        actor_field="uploads__library__actor", distinct=True
+    )
 
     class Meta:
         model = models.Track
@@ -52,6 +60,8 @@ class TrackFilter(moderation_filters.HiddenContentFilterSet):
             "artist": ["exact"],
             "album": ["exact"],
             "license": ["exact"],
+            "scope": ["exact"],
+            "mbid": ["exact"],
         }
         hidden_content_fields_mapping = moderation_filters.USER_FILTER_CONFIG["TRACK"]
 
@@ -67,6 +77,7 @@ class UploadFilter(filters.FilterSet):
     album_artist = filters.UUIDFilter("track__album__artist__uuid")
     library = filters.UUIDFilter("library__uuid")
     playable = filters.BooleanFilter(field_name="_", method="filter_playable")
+    scope = common_filters.ActorScopeFilter(actor_field="library__actor", distinct=True)
     q = fields.SmartSearchFilter(
         config=search.SearchConfig(
             search_fields={
@@ -96,6 +107,7 @@ class UploadFilter(filters.FilterSet):
             "album_artist",
             "library",
             "import_reference",
+            "scope",
         ]
 
     def filter_playable(self, queryset, name, value):
@@ -107,10 +119,13 @@ class AlbumFilter(moderation_filters.HiddenContentFilterSet):
     playable = filters.BooleanFilter(field_name="_", method="filter_playable")
     q = fields.SearchFilter(search_fields=["title", "artist__name"])
     tag = TAG_FILTER
+    scope = common_filters.ActorScopeFilter(
+        actor_field="tracks__uploads__library__actor", distinct=True
+    )
 
     class Meta:
         model = models.Album
-        fields = ["playable", "q", "artist"]
+        fields = ["playable", "q", "artist", "scope", "mbid"]
         hidden_content_fields_mapping = moderation_filters.USER_FILTER_CONFIG["ALBUM"]
 
     def filter_playable(self, queryset, name, value):
diff --git a/api/funkwhale_api/playlists/filters.py b/api/funkwhale_api/playlists/filters.py
index b204df4b0..43029a360 100644
--- a/api/funkwhale_api/playlists/filters.py
+++ b/api/funkwhale_api/playlists/filters.py
@@ -1,6 +1,7 @@
 from django.db.models import Count
 from django_filters import rest_framework as filters
 
+from funkwhale_api.common import filters as common_filters
 from funkwhale_api.music import utils
 
 from . import models
@@ -9,6 +10,7 @@ from . import models
 class PlaylistFilter(filters.FilterSet):
     q = filters.CharFilter(field_name="_", method="filter_q")
     playable = filters.BooleanFilter(field_name="_", method="filter_playable")
+    scope = common_filters.ActorScopeFilter(actor_field="user__actor", distinct=True)
 
     class Meta:
         model = models.Playlist
@@ -17,6 +19,7 @@ class PlaylistFilter(filters.FilterSet):
             "name": ["exact", "icontains"],
             "q": "exact",
             "playable": "exact",
+            "scope": "exact",
         }
 
     def filter_playable(self, queryset, name, value):
diff --git a/api/funkwhale_api/radios/filtersets.py b/api/funkwhale_api/radios/filtersets.py
index d8d7c9ed0..6f548dbea 100644
--- a/api/funkwhale_api/radios/filtersets.py
+++ b/api/funkwhale_api/radios/filtersets.py
@@ -1,9 +1,15 @@
 import django_filters
 
+from funkwhale_api.common import filters as common_filters
 from . import models
 
 
 class RadioFilter(django_filters.FilterSet):
+    scope = common_filters.ActorScopeFilter(actor_field="user__actor", distinct=True)
+
     class Meta:
         model = models.Radio
-        fields = {"name": ["exact", "iexact", "startswith", "icontains"]}
+        fields = {
+            "name": ["exact", "iexact", "startswith", "icontains"],
+            "scope": "exact",
+        }
diff --git a/api/tests/common/test_filters.py b/api/tests/common/test_filters.py
index 2e89dfa37..138f6ca5d 100644
--- a/api/tests/common/test_filters.py
+++ b/api/tests/common/test_filters.py
@@ -36,3 +36,53 @@ def test_mutation_filter_is_approved(value, expected, factories):
     )
 
     assert list(filterset.qs) == [mutations[expected]]
+
+
+@pytest.mark.parametrize(
+    "scope, user_index, expected_tracks",
+    [
+        ("me", 0, [0]),
+        ("me", 1, [1]),
+        ("me", 2, []),
+        ("all", 0, [0, 1, 2]),
+        ("all", 1, [0, 1, 2]),
+        ("all", 2, [0, 1, 2]),
+        ("noop", 0, []),
+        ("noop", 1, []),
+        ("noop", 2, []),
+    ],
+)
+def test_actor_scope_filter(
+    scope,
+    user_index,
+    expected_tracks,
+    queryset_equal_list,
+    factories,
+    mocker,
+    anonymous_user,
+):
+    actor1 = factories["users.User"]().create_actor()
+    actor2 = factories["users.User"]().create_actor()
+    users = [actor1.user, actor2.user, anonymous_user]
+    tracks = [
+        factories["music.Upload"](library__actor=actor1, playable=True).track,
+        factories["music.Upload"](library__actor=actor2, playable=True).track,
+        factories["music.Upload"](playable=True).track,
+    ]
+
+    class FS(filters.filters.FilterSet):
+        scope = filters.ActorScopeFilter(
+            actor_field="uploads__library__actor", distinct=True
+        )
+
+        class Meta:
+            model = tracks[0].__class__
+            fields = ["scope"]
+
+    queryset = tracks[0].__class__.objects.all()
+    request = mocker.Mock(user=users[user_index])
+    filterset = FS({"scope": scope}, queryset=queryset.order_by("id"), request=request)
+
+    expected = [tracks[i] for i in expected_tracks]
+
+    assert filterset.qs == expected
-- 
GitLab