Merge branch '432-tags-api' into 'develop'
See #432: API endpoints to query tags See merge request funkwhale/funkwhale!824
This commit is contained in:
commit
8ee5578693
|
@ -10,11 +10,12 @@ from funkwhale_api.common import routers as common_routers
|
|||
from funkwhale_api.music import views
|
||||
from funkwhale_api.playlists import views as playlists_views
|
||||
from funkwhale_api.subsonic.views import SubsonicViewSet
|
||||
from funkwhale_api.tags import views as tags_views
|
||||
|
||||
router = common_routers.OptionalSlashRouter()
|
||||
router.register(r"settings", GlobalPreferencesViewSet, basename="settings")
|
||||
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"uploads", views.UploadViewSet, "uploads")
|
||||
router.register(r"libraries", views.LibraryViewSet, "libraries")
|
||||
|
|
|
@ -51,7 +51,7 @@ def create_tagged_tracks(factories, count, dependencies):
|
|||
objs = []
|
||||
for track in dependencies["tracks"]:
|
||||
tag = random.choice(dependencies["tags"])
|
||||
objs.append(factories["tags.TaggedItem"](content_object=track, tag=tag))
|
||||
objs.append(factories["tags.TaggedItem"].build(content_object=track, tag=tag))
|
||||
|
||||
return tags_models.TaggedItem.objects.bulk_create(
|
||||
objs, batch_size=BATCH_SIZE, ignore_conflicts=True
|
||||
|
@ -217,27 +217,24 @@ class Command(BaseCommand):
|
|||
if not count:
|
||||
return []
|
||||
dependencies = row.get("depends_on", [])
|
||||
dependencies_results = {}
|
||||
create_dependencies = options.get("create_dependencies")
|
||||
for dependency in dependencies:
|
||||
if not create_dependencies:
|
||||
continue
|
||||
dep_count = options.get(dependency["id"])
|
||||
if not create_dependencies and dep_count is None:
|
||||
continue
|
||||
if dep_count is None:
|
||||
factor = options[
|
||||
"{}_{}_factor".format(row["id"], dependency["field"])
|
||||
] or dependency.get("default_factor")
|
||||
dep_count = math.ceil(factor * count)
|
||||
|
||||
dependencies_results[dependency["id"]] = self.create_batch(
|
||||
results[dependency["id"]] = self.create_batch(
|
||||
CONFIG_BY_ID[dependency["id"]], results, options, count=dep_count
|
||||
)
|
||||
self.stdout.write("Creating {} {}…".format(count, row["id"]))
|
||||
handler = row.get("handler")
|
||||
if handler:
|
||||
objects = handler(
|
||||
factories.registry, count, dependencies=dependencies_results
|
||||
)
|
||||
objects = handler(factories.registry, count, dependencies=results)
|
||||
else:
|
||||
objects = create_objects(
|
||||
row, factories.registry, count, **row.get("factory_kwargs", {})
|
||||
|
@ -246,7 +243,7 @@ class Command(BaseCommand):
|
|||
if not dependency.get("set", True):
|
||||
continue
|
||||
if create_dependencies:
|
||||
candidates = dependencies_results[dependency["id"]]
|
||||
candidates = results[dependency["id"]]
|
||||
else:
|
||||
# we use existing objects in the database
|
||||
queryset = dependency.get(
|
||||
|
|
|
@ -447,14 +447,6 @@ class UploadViewSet(
|
|||
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):
|
||||
max_results = 3
|
||||
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",
|
||||
),
|
||||
("api:v1:federation:library-follows-list", {}, "read:follows", "get"),
|
||||
("api:v1:tags-list", {}, "read:libraries", "get"),
|
||||
# admin / privileged stuff
|
||||
("api:v1:instance:admin-settings-list", {}, "read:instance:settings", "get"),
|
||||
(
|
||||
|
|
Loading…
Reference in New Issue