See #432: API endpoint to query tags
This commit is contained in:
parent
e11c1dfe29
commit
9f3076f4db
|
@ -10,11 +10,12 @@ from funkwhale_api.common import routers as common_routers
|
||||||
from funkwhale_api.music import views
|
from funkwhale_api.music import views
|
||||||
from funkwhale_api.playlists import views as playlists_views
|
from funkwhale_api.playlists import views as playlists_views
|
||||||
from funkwhale_api.subsonic.views import SubsonicViewSet
|
from funkwhale_api.subsonic.views import SubsonicViewSet
|
||||||
|
from funkwhale_api.tags import views as tags_views
|
||||||
|
|
||||||
router = common_routers.OptionalSlashRouter()
|
router = common_routers.OptionalSlashRouter()
|
||||||
router.register(r"settings", GlobalPreferencesViewSet, basename="settings")
|
router.register(r"settings", GlobalPreferencesViewSet, basename="settings")
|
||||||
router.register(r"activity", activity_views.ActivityViewSet, "activity")
|
router.register(r"activity", activity_views.ActivityViewSet, "activity")
|
||||||
router.register(r"tags", views.TagViewSet, "tags")
|
router.register(r"tags", tags_views.TagViewSet, "tags")
|
||||||
router.register(r"tracks", views.TrackViewSet, "tracks")
|
router.register(r"tracks", views.TrackViewSet, "tracks")
|
||||||
router.register(r"uploads", views.UploadViewSet, "uploads")
|
router.register(r"uploads", views.UploadViewSet, "uploads")
|
||||||
router.register(r"libraries", views.LibraryViewSet, "libraries")
|
router.register(r"libraries", views.LibraryViewSet, "libraries")
|
||||||
|
|
|
@ -447,14 +447,6 @@ class UploadViewSet(
|
||||||
instance.delete()
|
instance.delete()
|
||||||
|
|
||||||
|
|
||||||
class TagViewSet(viewsets.ReadOnlyModelViewSet):
|
|
||||||
queryset = Tag.objects.all().order_by("name")
|
|
||||||
serializer_class = serializers.TagSerializer
|
|
||||||
permission_classes = [oauth_permissions.ScopePermission]
|
|
||||||
required_scope = "libraries"
|
|
||||||
anonymous_policy = "setting"
|
|
||||||
|
|
||||||
|
|
||||||
class Search(views.APIView):
|
class Search(views.APIView):
|
||||||
max_results = 3
|
max_results = 3
|
||||||
permission_classes = [oauth_permissions.ScopePermission]
|
permission_classes = [oauth_permissions.ScopePermission]
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
import django_filters
|
||||||
|
from django_filters import rest_framework as filters
|
||||||
|
|
||||||
|
from funkwhale_api.common import fields
|
||||||
|
|
||||||
|
from . import models
|
||||||
|
|
||||||
|
|
||||||
|
class TagFilter(filters.FilterSet):
|
||||||
|
q = fields.SearchFilter(search_fields=["name"])
|
||||||
|
ordering = django_filters.OrderingFilter(
|
||||||
|
fields=(
|
||||||
|
("name", "name"),
|
||||||
|
("creation_date", "creation_date"),
|
||||||
|
("__size", "length"),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = models.Tag
|
||||||
|
fields = ["q"]
|
|
@ -0,0 +1,9 @@
|
||||||
|
from rest_framework import serializers
|
||||||
|
|
||||||
|
from . import models
|
||||||
|
|
||||||
|
|
||||||
|
class TagSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = models.Tag
|
||||||
|
fields = ["name", "creation_date"]
|
|
@ -0,0 +1,22 @@
|
||||||
|
from django.db.models import functions
|
||||||
|
from rest_framework import viewsets
|
||||||
|
|
||||||
|
from funkwhale_api.users.oauth import permissions as oauth_permissions
|
||||||
|
|
||||||
|
from . import filters
|
||||||
|
from . import models
|
||||||
|
from . import serializers
|
||||||
|
|
||||||
|
|
||||||
|
class TagViewSet(viewsets.ReadOnlyModelViewSet):
|
||||||
|
lookup_field = "name"
|
||||||
|
queryset = (
|
||||||
|
models.Tag.objects.all()
|
||||||
|
.annotate(__size=functions.Length("name"))
|
||||||
|
.order_by("name")
|
||||||
|
)
|
||||||
|
serializer_class = serializers.TagSerializer
|
||||||
|
permission_classes = [oauth_permissions.ScopePermission]
|
||||||
|
required_scope = "libraries"
|
||||||
|
anonymous_policy = "setting"
|
||||||
|
filterset_class = filters.TagFilter
|
|
@ -0,0 +1,16 @@
|
||||||
|
from funkwhale_api.tags import filters
|
||||||
|
from funkwhale_api.tags import models
|
||||||
|
|
||||||
|
|
||||||
|
def test_filter_search_tag(factories, queryset_equal_list):
|
||||||
|
matches = [
|
||||||
|
factories["tags.Tag"](name="Tag1"),
|
||||||
|
factories["tags.Tag"](name="TestTag1"),
|
||||||
|
factories["tags.Tag"](name="TestTag12"),
|
||||||
|
]
|
||||||
|
factories["tags.Tag"](name="TestTag")
|
||||||
|
factories["tags.Tag"](name="TestTag2")
|
||||||
|
qs = models.Tag.objects.all().order_by("name")
|
||||||
|
filterset = filters.TagFilter({"q": "tag1"}, queryset=qs)
|
||||||
|
|
||||||
|
assert filterset.qs == matches
|
|
@ -0,0 +1,14 @@
|
||||||
|
from funkwhale_api.tags import serializers
|
||||||
|
|
||||||
|
|
||||||
|
def test_tag_serializer(factories):
|
||||||
|
tag = factories["tags.Tag"]()
|
||||||
|
|
||||||
|
serializer = serializers.TagSerializer(tag)
|
||||||
|
|
||||||
|
expected = {
|
||||||
|
"name": tag.name,
|
||||||
|
"creation_date": tag.creation_date.isoformat().split("+")[0] + "Z",
|
||||||
|
}
|
||||||
|
|
||||||
|
assert serializer.data == expected
|
|
@ -0,0 +1,50 @@
|
||||||
|
from django.urls import reverse
|
||||||
|
|
||||||
|
from funkwhale_api.tags import serializers
|
||||||
|
|
||||||
|
|
||||||
|
def test_tags_list(factories, logged_in_api_client):
|
||||||
|
url = reverse("api:v1:tags-list")
|
||||||
|
tag = factories["tags.Tag"]()
|
||||||
|
|
||||||
|
expected = {
|
||||||
|
"count": 1,
|
||||||
|
"next": None,
|
||||||
|
"previous": None,
|
||||||
|
"results": [serializers.TagSerializer(tag).data],
|
||||||
|
}
|
||||||
|
|
||||||
|
response = logged_in_api_client.get(url)
|
||||||
|
|
||||||
|
assert response.data == expected
|
||||||
|
|
||||||
|
|
||||||
|
def test_tags_list_ordering_length(factories, logged_in_api_client):
|
||||||
|
url = reverse("api:v1:tags-list")
|
||||||
|
tags = [
|
||||||
|
factories["tags.Tag"](name="iamareallylongtag"),
|
||||||
|
factories["tags.Tag"](name="reallylongtag"),
|
||||||
|
factories["tags.Tag"](name="short"),
|
||||||
|
factories["tags.Tag"](name="bar"),
|
||||||
|
]
|
||||||
|
expected = {
|
||||||
|
"count": 4,
|
||||||
|
"next": None,
|
||||||
|
"previous": None,
|
||||||
|
"results": [serializers.TagSerializer(tag).data for tag in tags],
|
||||||
|
}
|
||||||
|
|
||||||
|
response = logged_in_api_client.get(url, {"ordering": "-length"})
|
||||||
|
|
||||||
|
assert response.data == expected
|
||||||
|
|
||||||
|
|
||||||
|
def test_tags_detail(factories, logged_in_api_client):
|
||||||
|
tag = factories["tags.Tag"]()
|
||||||
|
url = reverse("api:v1:tags-detail", kwargs={"name": tag.name})
|
||||||
|
|
||||||
|
expected = serializers.TagSerializer(tag).data
|
||||||
|
|
||||||
|
response = logged_in_api_client.get(url)
|
||||||
|
|
||||||
|
assert response.data == expected
|
|
@ -35,6 +35,7 @@ from funkwhale_api.users.oauth import scopes
|
||||||
"get",
|
"get",
|
||||||
),
|
),
|
||||||
("api:v1:federation:library-follows-list", {}, "read:follows", "get"),
|
("api:v1:federation:library-follows-list", {}, "read:follows", "get"),
|
||||||
|
("api:v1:tags-list", {}, "read:libraries", "get"),
|
||||||
# admin / privileged stuff
|
# admin / privileged stuff
|
||||||
("api:v1:instance:admin-settings-list", {}, "read:instance:settings", "get"),
|
("api:v1:instance:admin-settings-list", {}, "read:instance:settings", "get"),
|
||||||
(
|
(
|
||||||
|
|
Loading…
Reference in New Issue