diff --git a/api/funkwhale_api/radios/filters.py b/api/funkwhale_api/radios/filters.py index f3abe22e0..126701311 100644 --- a/api/funkwhale_api/radios/filters.py +++ b/api/funkwhale_api/radios/filters.py @@ -2,7 +2,7 @@ import collections import persisting_theory from django.core.exceptions import ValidationError -from django.db.models import Q +from django.db.models import Q, functions from django.urls import reverse_lazy from funkwhale_api.music import models @@ -132,9 +132,13 @@ class ArtistFilter(RadioFilter): "name": "ids", "type": "list", "subtype": "number", - "autocomplete": reverse_lazy("api:v1:artists-list"), + "autocomplete": reverse_lazy("api:v1:search"), "autocomplete_qs": "q={query}", - "autocomplete_fields": {"name": "name", "value": "id"}, + "autocomplete_fields": { + "remoteValues": "artists", + "name": "name", + "value": "id", + }, "label": "Artist", "placeholder": "Select artists", } @@ -145,7 +149,8 @@ class ArtistFilter(RadioFilter): filter_config["ids"] = sorted(filter_config["ids"]) names = ( models.Artist.objects.filter(pk__in=filter_config["ids"]) - .order_by("id") + .annotate(__size=functions.Length("name")) + .order_by("__size", "id") .values_list("name", flat=True) ) filter_config["names"] = list(names) @@ -176,13 +181,13 @@ class TagFilter(RadioFilter): "name": "names", "type": "list", "subtype": "string", - "autocomplete": reverse_lazy("api:v1:tags-list"), + "autocomplete": reverse_lazy("api:v1:search"), "autocomplete_fields": { - "remoteValues": "results", + "remoteValues": "tags", "name": "name", "value": "name", }, - "autocomplete_qs": "q={query}&ordering=length", + "autocomplete_qs": "q={query}", "label": "Tags", "placeholder": "Select tags", } @@ -196,3 +201,28 @@ class TagFilter(RadioFilter): | Q(artist__tagged_items__tag__name__in=names) | Q(album__tagged_items__tag__name__in=names) ) + + def clean_config(self, filter_config): + filter_config = super().clean_config(filter_config) + filter_config["names"] = sorted(filter_config["names"]) + names = ( + models.tags_models.Tag.objects.filter(name__in=filter_config["names"]) + .annotate(__size=functions.Length("name")) + .order_by("__size", "pk") + .values_list("name", flat=True) + ) + filter_config["names"] = list(names) + return filter_config + + def validate(self, config): + super().validate(config) + try: + names = models.tags_models.Tag.objects.filter( + name__in=config["names"] + ).values_list("name", flat=True) + diff = set(config["names"]) - set(names) + assert len(diff) == 0 + except KeyError: + raise ValidationError("You must provide a name") + except AssertionError: + raise ValidationError('No tag matching names "{}"'.format(diff)) diff --git a/api/tests/radios/test_filters.py b/api/tests/radios/test_filters.py new file mode 100644 index 000000000..d63ef7940 --- /dev/null +++ b/api/tests/radios/test_filters.py @@ -0,0 +1,37 @@ +from funkwhale_api.radios import filters + + +def test_clean_config_artist_name_sorting(factories): + + artist3 = factories["music.Artist"](name="The Green Eyes") + artist2 = factories["music.Artist"](name="The Green Eyed Machine") + artist1 = factories["music.Artist"](name="The Green Seed") + factories["music.Artist"]() + filter_config = {"type": "artist", "ids": [artist3.pk, artist1.pk, artist2.pk]} + artist_filter = filters.ArtistFilter() + config = artist_filter.clean_config(filter_config) + # list of names whose artists have been sorted by name then by id + sorted_names = [ + a.name + for a in list( + sorted([artist2, artist1, artist3], key=lambda x: (len(x.name), x.id)) + ) + ] + assert config["names"] == sorted_names + + +def test_clean_config_tag_name_sorting(factories): + + tag3 = factories["tags.Tag"](name="Rock") + tag2 = factories["tags.Tag"](name="Classic") + tag1 = factories["tags.Tag"](name="Punk") + factories["tags.Tag"]() + filter_config = {"type": "tag", "names": [tag3.name, tag1.name, tag2.name]} + tag_filter = filters.TagFilter() + config = tag_filter.clean_config(filter_config) + # list of names whose tags have been sorted by name then by id + sorted_names = [ + a.name + for a in list(sorted([tag2, tag1, tag3], key=lambda x: (len(x.name), x.id))) + ] + assert config["names"] == sorted_names diff --git a/changes/changelog.d/733.bugfix b/changes/changelog.d/733.bugfix new file mode 100644 index 000000000..3d8d199a8 --- /dev/null +++ b/changes/changelog.d/733.bugfix @@ -0,0 +1 @@ +Fixed search behaviour in radio builder's filters (#733)