mirror of
https://code.eliotberriot.com/funkwhale/funkwhale.git
synced 2025-10-06 03:39:55 +02:00
Resolve "Hide an artist in the UI"
This commit is contained in:
parent
d4d4e60e39
commit
bdf83bd8ff
50 changed files with 1051 additions and 49 deletions
30
api/tests/favorites/test_filters.py
Normal file
30
api/tests/favorites/test_filters.py
Normal file
|
@ -0,0 +1,30 @@
|
|||
from funkwhale_api.favorites import filters
|
||||
from funkwhale_api.favorites import models
|
||||
|
||||
|
||||
def test_track_favorite_filter_track_artist(factories, mocker, queryset_equal_list):
|
||||
factories["favorites.TrackFavorite"]()
|
||||
cf = factories["moderation.UserFilter"](for_artist=True)
|
||||
hidden_fav = factories["favorites.TrackFavorite"](track__artist=cf.target_artist)
|
||||
qs = models.TrackFavorite.objects.all()
|
||||
filterset = filters.TrackFavoriteFilter(
|
||||
{"hidden": "true"}, request=mocker.Mock(user=cf.user), queryset=qs
|
||||
)
|
||||
|
||||
assert filterset.qs == [hidden_fav]
|
||||
|
||||
|
||||
def test_track_favorite_filter_track_album_artist(
|
||||
factories, mocker, queryset_equal_list
|
||||
):
|
||||
factories["favorites.TrackFavorite"]()
|
||||
cf = factories["moderation.UserFilter"](for_artist=True)
|
||||
hidden_fav = factories["favorites.TrackFavorite"](
|
||||
track__album__artist=cf.target_artist
|
||||
)
|
||||
qs = models.TrackFavorite.objects.all()
|
||||
filterset = filters.TrackFavoriteFilter(
|
||||
{"hidden": "true"}, request=mocker.Mock(user=cf.user), queryset=qs
|
||||
)
|
||||
|
||||
assert filterset.qs == [hidden_fav]
|
28
api/tests/history/test_filters.py
Normal file
28
api/tests/history/test_filters.py
Normal file
|
@ -0,0 +1,28 @@
|
|||
from funkwhale_api.history import filters
|
||||
from funkwhale_api.history import models
|
||||
|
||||
|
||||
def test_listening_filter_track_artist(factories, mocker, queryset_equal_list):
|
||||
factories["history.Listening"]()
|
||||
cf = factories["moderation.UserFilter"](for_artist=True)
|
||||
hidden_listening = factories["history.Listening"](track__artist=cf.target_artist)
|
||||
qs = models.Listening.objects.all()
|
||||
filterset = filters.ListeningFilter(
|
||||
{"hidden": "true"}, request=mocker.Mock(user=cf.user), queryset=qs
|
||||
)
|
||||
|
||||
assert filterset.qs == [hidden_listening]
|
||||
|
||||
|
||||
def test_listening_filter_track_album_artist(factories, mocker, queryset_equal_list):
|
||||
factories["history.Listening"]()
|
||||
cf = factories["moderation.UserFilter"](for_artist=True)
|
||||
hidden_listening = factories["history.Listening"](
|
||||
track__album__artist=cf.target_artist
|
||||
)
|
||||
qs = models.Listening.objects.all()
|
||||
filterset = filters.ListeningFilter(
|
||||
{"hidden": "true"}, request=mocker.Mock(user=cf.user), queryset=qs
|
||||
)
|
||||
|
||||
assert filterset.qs == [hidden_listening]
|
0
api/tests/moderation/__init__.py
Normal file
0
api/tests/moderation/__init__.py
Normal file
68
api/tests/moderation/test_filters.py
Normal file
68
api/tests/moderation/test_filters.py
Normal file
|
@ -0,0 +1,68 @@
|
|||
from funkwhale_api.moderation import filters
|
||||
from funkwhale_api.music import models as music_models
|
||||
|
||||
|
||||
def test_hidden_defaults_to_true(factories, queryset_equal_list, mocker):
|
||||
user = factories["users.User"]()
|
||||
artist = factories["music.Artist"]()
|
||||
hidden_artist = factories["music.Artist"]()
|
||||
factories["moderation.UserFilter"](target_artist=hidden_artist, user=user)
|
||||
|
||||
class FS(filters.HiddenContentFilterSet):
|
||||
class Meta:
|
||||
hidden_content_fields_mapping = {"target_artist": ["pk"]}
|
||||
|
||||
filterset = FS(
|
||||
data={},
|
||||
queryset=music_models.Artist.objects.all(),
|
||||
request=mocker.Mock(user=user),
|
||||
)
|
||||
assert filterset.data["hidden"] is False
|
||||
queryset = filterset.filter_hidden_content(
|
||||
music_models.Artist.objects.all(), "", False
|
||||
)
|
||||
|
||||
assert queryset == [artist]
|
||||
|
||||
|
||||
def test_hidden_false(factories, queryset_equal_list, mocker):
|
||||
user = factories["users.User"]()
|
||||
factories["music.Artist"]()
|
||||
hidden_artist = factories["music.Artist"]()
|
||||
factories["moderation.UserFilter"](target_artist=hidden_artist, user=user)
|
||||
|
||||
class FS(filters.HiddenContentFilterSet):
|
||||
class Meta:
|
||||
hidden_content_fields_mapping = {"target_artist": ["pk"]}
|
||||
|
||||
filterset = FS(
|
||||
data={},
|
||||
queryset=music_models.Artist.objects.all(),
|
||||
request=mocker.Mock(user=user),
|
||||
)
|
||||
|
||||
queryset = filterset.filter_hidden_content(
|
||||
music_models.Artist.objects.all(), "", True
|
||||
)
|
||||
|
||||
assert queryset == [hidden_artist]
|
||||
|
||||
|
||||
def test_hidden_anonymous(factories, queryset_equal_list, mocker, anonymous_user):
|
||||
artist = factories["music.Artist"]()
|
||||
|
||||
class FS(filters.HiddenContentFilterSet):
|
||||
class Meta:
|
||||
hidden_content_fields_mapping = {"target_artist": ["pk"]}
|
||||
|
||||
filterset = FS(
|
||||
data={},
|
||||
queryset=music_models.Artist.objects.all(),
|
||||
request=mocker.Mock(user=anonymous_user),
|
||||
)
|
||||
|
||||
queryset = filterset.filter_hidden_content(
|
||||
music_models.Artist.objects.all(), "", True
|
||||
)
|
||||
|
||||
assert queryset == [artist]
|
30
api/tests/moderation/test_serializers.py
Normal file
30
api/tests/moderation/test_serializers.py
Normal file
|
@ -0,0 +1,30 @@
|
|||
from funkwhale_api.moderation import serializers
|
||||
|
||||
|
||||
def test_user_filter_serializer_repr(factories):
|
||||
artist = factories["music.Artist"]()
|
||||
content_filter = factories["moderation.UserFilter"](target_artist=artist)
|
||||
|
||||
expected = {
|
||||
"uuid": str(content_filter.uuid),
|
||||
"target": {"type": "artist", "id": artist.pk, "name": artist.name},
|
||||
"creation_date": content_filter.creation_date.isoformat().replace(
|
||||
"+00:00", "Z"
|
||||
),
|
||||
}
|
||||
|
||||
serializer = serializers.UserFilterSerializer(content_filter)
|
||||
|
||||
assert serializer.data == expected
|
||||
|
||||
|
||||
def test_user_filter_serializer_save(factories):
|
||||
artist = factories["music.Artist"]()
|
||||
user = factories["users.User"]()
|
||||
data = {"target": {"type": "artist", "id": artist.pk}}
|
||||
|
||||
serializer = serializers.UserFilterSerializer(data=data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
content_filter = serializer.save(user=user)
|
||||
|
||||
assert content_filter.target_artist == artist
|
24
api/tests/moderation/test_views.py
Normal file
24
api/tests/moderation/test_views.py
Normal file
|
@ -0,0 +1,24 @@
|
|||
from django.urls import reverse
|
||||
|
||||
|
||||
def test_restrict_to_own_filters(factories, logged_in_api_client):
|
||||
cf = factories["moderation.UserFilter"](
|
||||
for_artist=True, user=logged_in_api_client.user
|
||||
)
|
||||
factories["moderation.UserFilter"](for_artist=True)
|
||||
url = reverse("api:v1:moderation:content-filters-list")
|
||||
response = logged_in_api_client.get(url)
|
||||
assert response.status_code == 200
|
||||
assert response.data["count"] == 1
|
||||
assert response.data["results"][0]["uuid"] == str(cf.uuid)
|
||||
|
||||
|
||||
def test_create_filter(factories, logged_in_api_client):
|
||||
artist = factories["music.Artist"]()
|
||||
url = reverse("api:v1:moderation:content-filters-list")
|
||||
data = {"target": {"type": "artist", "id": artist.pk}}
|
||||
response = logged_in_api_client.post(url, data, format="json")
|
||||
|
||||
cf = logged_in_api_client.user.content_filters.latest("id")
|
||||
assert cf.target_artist == artist
|
||||
assert response.status_code == 201
|
54
api/tests/music/test_filters.py
Normal file
54
api/tests/music/test_filters.py
Normal file
|
@ -0,0 +1,54 @@
|
|||
from funkwhale_api.music import filters
|
||||
from funkwhale_api.music import models
|
||||
|
||||
|
||||
def test_album_filter_hidden(factories, mocker, queryset_equal_list):
|
||||
factories["music.Album"]()
|
||||
cf = factories["moderation.UserFilter"](for_artist=True)
|
||||
hidden_album = factories["music.Album"](artist=cf.target_artist)
|
||||
|
||||
qs = models.Album.objects.all()
|
||||
filterset = filters.AlbumFilter(
|
||||
{"hidden": "true"}, request=mocker.Mock(user=cf.user), queryset=qs
|
||||
)
|
||||
|
||||
assert filterset.qs == [hidden_album]
|
||||
|
||||
|
||||
def test_artist_filter_hidden(factories, mocker, queryset_equal_list):
|
||||
factories["music.Artist"]()
|
||||
cf = factories["moderation.UserFilter"](for_artist=True)
|
||||
hidden_artist = cf.target_artist
|
||||
|
||||
qs = models.Artist.objects.all()
|
||||
filterset = filters.ArtistFilter(
|
||||
{"hidden": "true"}, request=mocker.Mock(user=cf.user), queryset=qs
|
||||
)
|
||||
|
||||
assert filterset.qs == [hidden_artist]
|
||||
|
||||
|
||||
def test_artist_filter_track_artist(factories, mocker, queryset_equal_list):
|
||||
factories["music.Track"]()
|
||||
cf = factories["moderation.UserFilter"](for_artist=True)
|
||||
hidden_track = factories["music.Track"](artist=cf.target_artist)
|
||||
|
||||
qs = models.Track.objects.all()
|
||||
filterset = filters.TrackFilter(
|
||||
{"hidden": "true"}, request=mocker.Mock(user=cf.user), queryset=qs
|
||||
)
|
||||
|
||||
assert filterset.qs == [hidden_track]
|
||||
|
||||
|
||||
def test_artist_filter_track_album_artist(factories, mocker, queryset_equal_list):
|
||||
factories["music.Track"]()
|
||||
cf = factories["moderation.UserFilter"](for_artist=True)
|
||||
hidden_track = factories["music.Track"](album__artist=cf.target_artist)
|
||||
|
||||
qs = models.Track.objects.all()
|
||||
filterset = filters.TrackFilter(
|
||||
{"hidden": "true"}, request=mocker.Mock(user=cf.user), queryset=qs
|
||||
)
|
||||
|
||||
assert filterset.qs == [hidden_track]
|
|
@ -254,3 +254,27 @@ def test_similar_radio_track(factories):
|
|||
factories["history.Listening"](track=expected_next, user=l1.user)
|
||||
|
||||
assert radio.pick(filter_playable=False) == expected_next
|
||||
|
||||
|
||||
def test_session_radio_get_queryset_ignore_filtered_track_artist(
|
||||
factories, queryset_equal_list
|
||||
):
|
||||
cf = factories["moderation.UserFilter"](for_artist=True)
|
||||
factories["music.Track"](artist=cf.target_artist)
|
||||
valid_track = factories["music.Track"]()
|
||||
radio = radios.RandomRadio()
|
||||
radio.start_session(user=cf.user)
|
||||
|
||||
assert radio.get_queryset() == [valid_track]
|
||||
|
||||
|
||||
def test_session_radio_get_queryset_ignore_filtered_track_album_artist(
|
||||
factories, queryset_equal_list
|
||||
):
|
||||
cf = factories["moderation.UserFilter"](for_artist=True)
|
||||
factories["music.Track"](album__artist=cf.target_artist)
|
||||
valid_track = factories["music.Track"]()
|
||||
radio = radios.RandomRadio()
|
||||
radio.start_session(user=cf.user)
|
||||
|
||||
assert radio.get_queryset() == [valid_track]
|
||||
|
|
|
@ -7,6 +7,7 @@ from django.utils import timezone
|
|||
from rest_framework.response import Response
|
||||
|
||||
import funkwhale_api
|
||||
from funkwhale_api.moderation import filters as moderation_filters
|
||||
from funkwhale_api.music import models as music_models
|
||||
from funkwhale_api.music import views as music_views
|
||||
from funkwhale_api.subsonic import renderers, serializers
|
||||
|
@ -100,20 +101,31 @@ def test_ping(f, db, api_client):
|
|||
def test_get_artists(
|
||||
f, db, logged_in_api_client, factories, mocker, queryset_equal_queries
|
||||
):
|
||||
factories["moderation.UserFilter"](
|
||||
user=logged_in_api_client.user,
|
||||
target_artist=factories["music.Artist"](playable=True),
|
||||
)
|
||||
url = reverse("api:subsonic-get_artists")
|
||||
assert url.endswith("getArtists") is True
|
||||
factories["music.Artist"].create_batch(size=3, playable=True)
|
||||
playable_by = mocker.spy(music_models.ArtistQuerySet, "playable_by")
|
||||
exclude_query = moderation_filters.get_filtered_content_query(
|
||||
moderation_filters.USER_FILTER_CONFIG["ARTIST"], logged_in_api_client.user
|
||||
)
|
||||
assert exclude_query is not None
|
||||
expected = {
|
||||
"artists": serializers.GetArtistsSerializer(
|
||||
music_models.Artist.objects.all()
|
||||
music_models.Artist.objects.all().exclude(exclude_query)
|
||||
).data
|
||||
}
|
||||
response = logged_in_api_client.get(url, {"f": f})
|
||||
|
||||
assert response.status_code == 200
|
||||
assert response.data == expected
|
||||
playable_by.assert_called_once_with(music_models.Artist.objects.all(), None)
|
||||
playable_by.assert_called_once_with(
|
||||
music_models.Artist.objects.all().exclude(exclude_query),
|
||||
logged_in_api_client.user.actor,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("f", ["json"])
|
||||
|
@ -502,12 +514,20 @@ def test_get_music_folders(f, db, logged_in_api_client, factories):
|
|||
def test_get_indexes(
|
||||
f, db, logged_in_api_client, factories, mocker, queryset_equal_queries
|
||||
):
|
||||
factories["moderation.UserFilter"](
|
||||
user=logged_in_api_client.user,
|
||||
target_artist=factories["music.Artist"](playable=True),
|
||||
)
|
||||
exclude_query = moderation_filters.get_filtered_content_query(
|
||||
moderation_filters.USER_FILTER_CONFIG["ARTIST"], logged_in_api_client.user
|
||||
)
|
||||
|
||||
url = reverse("api:subsonic-get_indexes")
|
||||
assert url.endswith("getIndexes") is True
|
||||
factories["music.Artist"].create_batch(size=3, playable=True)
|
||||
expected = {
|
||||
"indexes": serializers.GetArtistsSerializer(
|
||||
music_models.Artist.objects.all()
|
||||
music_models.Artist.objects.all().exclude(exclude_query)
|
||||
).data
|
||||
}
|
||||
playable_by = mocker.spy(music_models.ArtistQuerySet, "playable_by")
|
||||
|
@ -516,7 +536,10 @@ def test_get_indexes(
|
|||
assert response.status_code == 200
|
||||
assert response.data == expected
|
||||
|
||||
playable_by.assert_called_once_with(music_models.Artist.objects.all(), None)
|
||||
playable_by.assert_called_once_with(
|
||||
music_models.Artist.objects.all().exclude(exclude_query),
|
||||
logged_in_api_client.user.actor,
|
||||
)
|
||||
|
||||
|
||||
def test_get_cover_art_album(factories, logged_in_api_client):
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue