Skip to content
Snippets Groups Projects
Verified Commit 13f36bee authored by Eliot Berriot's avatar Eliot Berriot
Browse files

See #432: added admin API endpoints to retrieve and delete tags

parent c885c10b
No related branches found
No related tags found
No related merge requests found
...@@ -13,6 +13,7 @@ from funkwhale_api.federation import utils as federation_utils ...@@ -13,6 +13,7 @@ from funkwhale_api.federation import utils as federation_utils
from funkwhale_api.moderation import models as moderation_models from funkwhale_api.moderation import models as moderation_models
from funkwhale_api.music import models as music_models from funkwhale_api.music import models as music_models
from funkwhale_api.users import models as users_models from funkwhale_api.users import models as users_models
from funkwhale_api.tags import models as tags_models
class ActorField(forms.CharField): class ActorField(forms.CharField):
...@@ -340,3 +341,11 @@ class ManageInstancePolicyFilterSet(filters.FilterSet): ...@@ -340,3 +341,11 @@ class ManageInstancePolicyFilterSet(filters.FilterSet):
"silence_notifications", "silence_notifications",
"reject_media", "reject_media",
] ]
class ManageTagFilterSet(filters.FilterSet):
q = fields.SearchFilter(search_fields=["name"])
class Meta:
model = tags_models.Tag
fields = ["q"]
...@@ -10,6 +10,7 @@ from funkwhale_api.federation import tasks as federation_tasks ...@@ -10,6 +10,7 @@ from funkwhale_api.federation import tasks as federation_tasks
from funkwhale_api.moderation import models as moderation_models from funkwhale_api.moderation import models as moderation_models
from funkwhale_api.music import models as music_models from funkwhale_api.music import models as music_models
from funkwhale_api.music import serializers as music_serializers from funkwhale_api.music import serializers as music_serializers
from funkwhale_api.tags import models as tags_models
from funkwhale_api.users import models as users_models from funkwhale_api.users import models as users_models
from . import filters from . import filters
...@@ -564,3 +565,30 @@ class ManageUploadSerializer(serializers.ModelSerializer): ...@@ -564,3 +565,30 @@ class ManageUploadSerializer(serializers.ModelSerializer):
"track", "track",
"library", "library",
) )
class ManageTagSerializer(ManageBaseAlbumSerializer):
tracks_count = serializers.SerializerMethodField()
albums_count = serializers.SerializerMethodField()
artists_count = serializers.SerializerMethodField()
class Meta:
model = tags_models.Tag
fields = [
"id",
"name",
"creation_date",
"tracks_count",
"albums_count",
"artists_count",
]
def get_tracks_count(self, obj):
return getattr(obj, "_tracks_count", None)
def get_albums_count(self, obj):
return getattr(obj, "_albums_count", None)
def get_artists_count(self, obj):
return getattr(obj, "_artists_count", None)
...@@ -24,6 +24,7 @@ users_router.register(r"invitations", views.ManageInvitationViewSet, "invitation ...@@ -24,6 +24,7 @@ users_router.register(r"invitations", views.ManageInvitationViewSet, "invitation
other_router = routers.OptionalSlashRouter() other_router = routers.OptionalSlashRouter()
other_router.register(r"accounts", views.ManageActorViewSet, "accounts") other_router.register(r"accounts", views.ManageActorViewSet, "accounts")
other_router.register(r"tags", views.ManageTagViewSet, "tags")
urlpatterns = [ urlpatterns = [
url( url(
......
...@@ -2,7 +2,7 @@ from rest_framework import mixins, response, viewsets ...@@ -2,7 +2,7 @@ from rest_framework import mixins, response, viewsets
from rest_framework import decorators as rest_decorators from rest_framework import decorators as rest_decorators
from django.db.models import Count, Prefetch, Q, Sum, OuterRef, Subquery from django.db.models import Count, Prefetch, Q, Sum, OuterRef, Subquery
from django.db.models.functions import Coalesce from django.db.models.functions import Coalesce, Length
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
from funkwhale_api.common import models as common_models from funkwhale_api.common import models as common_models
...@@ -14,6 +14,7 @@ from funkwhale_api.history import models as history_models ...@@ -14,6 +14,7 @@ from funkwhale_api.history import models as history_models
from funkwhale_api.music import models as music_models from funkwhale_api.music import models as music_models
from funkwhale_api.moderation import models as moderation_models from funkwhale_api.moderation import models as moderation_models
from funkwhale_api.playlists import models as playlists_models from funkwhale_api.playlists import models as playlists_models
from funkwhale_api.tags import models as tags_models
from funkwhale_api.users import models as users_models from funkwhale_api.users import models as users_models
...@@ -452,3 +453,43 @@ class ManageInstancePolicyViewSet( ...@@ -452,3 +453,43 @@ class ManageInstancePolicyViewSet(
def perform_create(self, serializer): def perform_create(self, serializer):
serializer.save(actor=self.request.user.actor) serializer.save(actor=self.request.user.actor)
class ManageTagViewSet(
mixins.ListModelMixin,
mixins.RetrieveModelMixin,
mixins.DestroyModelMixin,
mixins.CreateModelMixin,
viewsets.GenericViewSet,
):
lookup_field = "name"
queryset = (
tags_models.Tag.objects.all()
.order_by("-creation_date")
.annotate(items_count=Count("tagged_items"))
.annotate(length=Length("name"))
)
serializer_class = serializers.ManageTagSerializer
filterset_class = filters.ManageTagFilterSet
required_scope = "instance:libraries"
ordering_fields = ["id", "creation_date", "name", "items_count", "length"]
def get_queryset(self):
queryset = super().get_queryset()
from django.contrib.contenttypes.models import ContentType
album_ct = ContentType.objects.get_for_model(music_models.Album)
track_ct = ContentType.objects.get_for_model(music_models.Track)
artist_ct = ContentType.objects.get_for_model(music_models.Artist)
queryset = queryset.annotate(
_albums_count=Count(
"tagged_items", filter=Q(tagged_items__content_type=album_ct)
),
_tracks_count=Count(
"tagged_items", filter=Q(tagged_items__content_type=track_ct)
),
_artists_count=Count(
"tagged_items", filter=Q(tagged_items__content_type=artist_ct)
),
)
return queryset
...@@ -496,3 +496,22 @@ def test_action_serializer_delete(factory, serializer_class, factories): ...@@ -496,3 +496,22 @@ def test_action_serializer_delete(factory, serializer_class, factories):
s.handle_delete(objects[0].__class__.objects.all()) s.handle_delete(objects[0].__class__.objects.all())
assert objects[0].__class__.objects.count() == 0 assert objects[0].__class__.objects.count() == 0
def test_manage_tag_serializer(factories):
tag = factories["tags.Tag"]()
setattr(tag, "_tracks_count", 42)
setattr(tag, "_albums_count", 54)
setattr(tag, "_artists_count", 66)
expected = {
"id": tag.id,
"name": tag.name,
"creation_date": tag.creation_date.isoformat().split("+")[0] + "Z",
"tracks_count": 42,
"albums_count": 54,
"artists_count": 66,
}
s = serializers.ManageTagSerializer(tag)
assert s.data == expected
...@@ -377,3 +377,31 @@ def test_upload_delete(factories, superuser_api_client): ...@@ -377,3 +377,31 @@ def test_upload_delete(factories, superuser_api_client):
response = superuser_api_client.delete(url) response = superuser_api_client.delete(url)
assert response.status_code == 204 assert response.status_code == 204
def test_tag_detail(factories, superuser_api_client):
tag = factories["tags.Tag"]()
url = reverse("api:v1:manage:tags-detail", kwargs={"name": tag.name})
response = superuser_api_client.get(url)
assert response.status_code == 200
assert response.data["name"] == tag.name
def test_tag_list(factories, superuser_api_client, settings):
tag = factories["tags.Tag"]()
url = reverse("api:v1:manage:tags-list")
response = superuser_api_client.get(url)
assert response.status_code == 200
assert response.data["count"] == 1
assert response.data["results"][0]["name"] == tag.name
def test_tag_delete(factories, superuser_api_client):
tag = factories["tags.Tag"]()
url = reverse("api:v1:manage:tags-detail", kwargs={"name": tag.name})
response = superuser_api_client.delete(url)
assert response.status_code == 204
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment