kopia lustrzana https://dev.funkwhale.audio/funkwhale/funkwhale
				
				
				
			Updated rest framework to 3.9
							rodzic
							
								
									4a6df06360
								
							
						
					
					
						commit
						14392ebb0c
					
				|  | @ -10,7 +10,7 @@ from funkwhale_api.playlists import views as playlists_views | |||
| from funkwhale_api.subsonic.views import SubsonicViewSet | ||||
| 
 | ||||
| router = routers.SimpleRouter() | ||||
| router.register(r"settings", GlobalPreferencesViewSet, base_name="settings") | ||||
| 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"tracks", views.TrackViewSet, "tracks") | ||||
|  | @ -27,7 +27,7 @@ router.register( | |||
| v1_patterns = router.urls | ||||
| 
 | ||||
| subsonic_router = routers.SimpleRouter(trailing_slash=False) | ||||
| subsonic_router.register(r"subsonic/rest", SubsonicViewSet, base_name="subsonic") | ||||
| subsonic_router.register(r"subsonic/rest", SubsonicViewSet, basename="subsonic") | ||||
| 
 | ||||
| 
 | ||||
| v1_patterns += [ | ||||
|  |  | |||
|  | @ -1,9 +1,9 @@ | |||
| from rest_framework import response | ||||
| from rest_framework.decorators import list_route | ||||
| from rest_framework import decorators | ||||
| 
 | ||||
| 
 | ||||
| def action_route(serializer_class): | ||||
|     @list_route(methods=["post"]) | ||||
|     @decorators.action(methods=["post"], detail=False) | ||||
|     def action(self, request, *args, **kwargs): | ||||
|         queryset = self.get_queryset() | ||||
|         serializer = serializer_class(request.data, queryset=queryset) | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| from rest_framework import mixins, status, viewsets | ||||
| from rest_framework.decorators import list_route | ||||
| from rest_framework.decorators import action | ||||
| from rest_framework.permissions import IsAuthenticatedOrReadOnly | ||||
| from rest_framework.response import Response | ||||
| 
 | ||||
|  | @ -62,7 +62,7 @@ class TrackFavoriteViewSet( | |||
|         favorite = models.TrackFavorite.add(track=track, user=self.request.user) | ||||
|         return favorite | ||||
| 
 | ||||
|     @list_route(methods=["delete", "post"]) | ||||
|     @action(methods=["delete", "post"], detail=False) | ||||
|     def remove(self, request, *args, **kwargs): | ||||
|         try: | ||||
|             pk = int(request.data["track"]) | ||||
|  | @ -72,7 +72,7 @@ class TrackFavoriteViewSet( | |||
|         favorite.delete() | ||||
|         return Response([], status=status.HTTP_204_NO_CONTENT) | ||||
| 
 | ||||
|     @list_route(methods=["get"]) | ||||
|     @action(methods=["get"], detail=False) | ||||
|     def all(self, request, *args, **kwargs): | ||||
|         """ | ||||
|         Return all the favorites of the current user, with only limited data | ||||
|  |  | |||
|  | @ -66,7 +66,7 @@ class LibraryFollowViewSet( | |||
|         context["actor"] = self.request.user.actor | ||||
|         return context | ||||
| 
 | ||||
|     @decorators.detail_route(methods=["post"]) | ||||
|     @decorators.action(methods=["post"], detail=True) | ||||
|     def accept(self, request, *args, **kwargs): | ||||
|         try: | ||||
|             follow = self.queryset.get( | ||||
|  | @ -77,7 +77,7 @@ class LibraryFollowViewSet( | |||
|         update_follow(follow, approved=True) | ||||
|         return response.Response(status=204) | ||||
| 
 | ||||
|     @decorators.detail_route(methods=["post"]) | ||||
|     @decorators.action(methods=["post"], detail=True) | ||||
|     def reject(self, request, *args, **kwargs): | ||||
|         try: | ||||
|             follow = self.queryset.get( | ||||
|  | @ -105,7 +105,7 @@ class LibraryViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet): | |||
|         qs = super().get_queryset() | ||||
|         return qs.viewable_by(actor=self.request.user.actor) | ||||
| 
 | ||||
|     @decorators.detail_route(methods=["post"]) | ||||
|     @decorators.action(methods=["post"], detail=True) | ||||
|     def scan(self, request, *args, **kwargs): | ||||
|         library = self.get_object() | ||||
|         if library.actor.get_user(): | ||||
|  | @ -122,7 +122,7 @@ class LibraryViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet): | |||
|             ) | ||||
|         return response.Response({"status": "skipped"}, 200) | ||||
| 
 | ||||
|     @decorators.list_route(methods=["post"]) | ||||
|     @decorators.action(methods=["post"], detail=False) | ||||
|     def fetch(self, request, *args, **kwargs): | ||||
|         try: | ||||
|             fid = request.data["fid"] | ||||
|  | @ -175,7 +175,7 @@ class InboxItemViewSet( | |||
|         qs = super().get_queryset() | ||||
|         return qs.filter(actor=self.request.user.actor) | ||||
| 
 | ||||
|     @decorators.list_route(methods=["post"]) | ||||
|     @decorators.action(methods=["post"], detail=False) | ||||
|     def action(self, request, *args, **kwargs): | ||||
|         queryset = self.get_queryset() | ||||
|         serializer = api_serializers.InboxItemActionSerializer( | ||||
|  |  | |||
|  | @ -3,7 +3,7 @@ from django.core import paginator | |||
| from django.http import HttpResponse | ||||
| from django.urls import reverse | ||||
| from rest_framework import exceptions, mixins, response, viewsets | ||||
| from rest_framework.decorators import detail_route, list_route | ||||
| from rest_framework.decorators import action | ||||
| 
 | ||||
| from funkwhale_api.common import preferences | ||||
| from funkwhale_api.music import models as music_models | ||||
|  | @ -23,7 +23,7 @@ class SharedViewSet(FederationMixin, viewsets.GenericViewSet): | |||
|     authentication_classes = [authentication.SignatureAuthentication] | ||||
|     renderer_classes = [renderers.ActivityPubRenderer] | ||||
| 
 | ||||
|     @list_route(methods=["post"]) | ||||
|     @action(methods=["post"], detail=False) | ||||
|     def inbox(self, request, *args, **kwargs): | ||||
|         if request.method.lower() == "post" and request.actor is None: | ||||
|             raise exceptions.AuthenticationFailed( | ||||
|  | @ -42,7 +42,7 @@ class ActorViewSet(FederationMixin, mixins.RetrieveModelMixin, viewsets.GenericV | |||
|     queryset = models.Actor.objects.local().select_related("user") | ||||
|     serializer_class = serializers.ActorSerializer | ||||
| 
 | ||||
|     @detail_route(methods=["get", "post"]) | ||||
|     @action(methods=["get", "post"], detail=True) | ||||
|     def inbox(self, request, *args, **kwargs): | ||||
|         if request.method.lower() == "post" and request.actor is None: | ||||
|             raise exceptions.AuthenticationFailed( | ||||
|  | @ -52,17 +52,17 @@ class ActorViewSet(FederationMixin, mixins.RetrieveModelMixin, viewsets.GenericV | |||
|             activity.receive(activity=request.data, on_behalf_of=request.actor) | ||||
|         return response.Response({}, status=200) | ||||
| 
 | ||||
|     @detail_route(methods=["get", "post"]) | ||||
|     @action(methods=["get", "post"], detail=True) | ||||
|     def outbox(self, request, *args, **kwargs): | ||||
|         return response.Response({}, status=200) | ||||
| 
 | ||||
|     @detail_route(methods=["get"]) | ||||
|     @action(methods=["get"], detail=True) | ||||
|     def followers(self, request, *args, **kwargs): | ||||
|         self.get_object() | ||||
|         # XXX to implement | ||||
|         return response.Response({}) | ||||
| 
 | ||||
|     @detail_route(methods=["get"]) | ||||
|     @action(methods=["get"], detail=True) | ||||
|     def following(self, request, *args, **kwargs): | ||||
|         self.get_object() | ||||
|         # XXX to implement | ||||
|  | @ -74,7 +74,7 @@ class WellKnownViewSet(viewsets.GenericViewSet): | |||
|     permission_classes = [] | ||||
|     renderer_classes = [renderers.JSONRenderer, renderers.WebfingerRenderer] | ||||
| 
 | ||||
|     @list_route(methods=["get"]) | ||||
|     @action(methods=["get"], detail=False) | ||||
|     def nodeinfo(self, request, *args, **kwargs): | ||||
|         if not preferences.get("instance__nodeinfo_enabled"): | ||||
|             return HttpResponse(status=404) | ||||
|  | @ -88,7 +88,7 @@ class WellKnownViewSet(viewsets.GenericViewSet): | |||
|         } | ||||
|         return response.Response(data) | ||||
| 
 | ||||
|     @list_route(methods=["get"]) | ||||
|     @action(methods=["get"], detail=False) | ||||
|     def webfinger(self, request, *args, **kwargs): | ||||
|         if not preferences.get("federation__enabled"): | ||||
|             return HttpResponse(status=405) | ||||
|  | @ -180,7 +180,7 @@ class MusicLibraryViewSet( | |||
| 
 | ||||
|         return response.Response(data) | ||||
| 
 | ||||
|     @detail_route(methods=["get"]) | ||||
|     @action(methods=["get"], detail=True) | ||||
|     def followers(self, request, *args, **kwargs): | ||||
|         self.get_object() | ||||
|         # XXX Implement this | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| from rest_framework import mixins, response, viewsets | ||||
| from rest_framework.decorators import detail_route, list_route | ||||
| from rest_framework import decorators as rest_decorators | ||||
| from django.shortcuts import get_object_or_404 | ||||
| 
 | ||||
| from funkwhale_api.common import preferences, decorators | ||||
|  | @ -35,7 +35,7 @@ class ManageUploadViewSet( | |||
|         "duration", | ||||
|     ] | ||||
| 
 | ||||
|     @list_route(methods=["post"]) | ||||
|     @rest_decorators.action(methods=["post"], detail=False) | ||||
|     def action(self, request, *args, **kwargs): | ||||
|         queryset = self.get_queryset() | ||||
|         serializer = serializers.ManageUploadActionSerializer( | ||||
|  | @ -87,7 +87,7 @@ class ManageInvitationViewSet( | |||
|     def perform_create(self, serializer): | ||||
|         serializer.save(owner=self.request.user) | ||||
| 
 | ||||
|     @list_route(methods=["post"]) | ||||
|     @rest_decorators.action(methods=["post"], detail=False) | ||||
|     def action(self, request, *args, **kwargs): | ||||
|         queryset = self.get_queryset() | ||||
|         serializer = serializers.ManageInvitationActionSerializer( | ||||
|  | @ -125,14 +125,14 @@ class ManageDomainViewSet( | |||
|         "instance_policy", | ||||
|     ] | ||||
| 
 | ||||
|     @detail_route(methods=["get"]) | ||||
|     @rest_decorators.action(methods=["get"], detail=True) | ||||
|     def nodeinfo(self, request, *args, **kwargs): | ||||
|         domain = self.get_object() | ||||
|         federation_tasks.update_domain_nodeinfo(domain_name=domain.name) | ||||
|         domain.refresh_from_db() | ||||
|         return response.Response(domain.nodeinfo, status=200) | ||||
| 
 | ||||
|     @detail_route(methods=["get"]) | ||||
|     @rest_decorators.action(methods=["get"], detail=True) | ||||
|     def stats(self, request, *args, **kwargs): | ||||
|         domain = self.get_object() | ||||
|         return response.Response(domain.get_stats(), status=200) | ||||
|  | @ -176,7 +176,7 @@ class ManageActorViewSet( | |||
| 
 | ||||
|         return obj | ||||
| 
 | ||||
|     @detail_route(methods=["get"]) | ||||
|     @rest_decorators.action(methods=["get"], detail=True) | ||||
|     def stats(self, request, *args, **kwargs): | ||||
|         domain = self.get_object() | ||||
|         return response.Response(domain.get_stats(), status=200) | ||||
|  |  | |||
|  | @ -11,7 +11,7 @@ from rest_framework import mixins | |||
| from rest_framework import permissions | ||||
| from rest_framework import settings as rest_settings | ||||
| from rest_framework import views, viewsets | ||||
| from rest_framework.decorators import detail_route, list_route | ||||
| from rest_framework.decorators import action | ||||
| from rest_framework.response import Response | ||||
| from taggit.models import Tag | ||||
| 
 | ||||
|  | @ -28,25 +28,25 @@ logger = logging.getLogger(__name__) | |||
| 
 | ||||
| 
 | ||||
| def get_libraries(filter_uploads): | ||||
|     def view(self, request, *args, **kwargs): | ||||
|     def libraries(self, request, *args, **kwargs): | ||||
|         obj = self.get_object() | ||||
|         actor = utils.get_actor_from_request(request) | ||||
|         uploads = models.Upload.objects.all() | ||||
|         uploads = filter_uploads(obj, uploads) | ||||
|         uploads = uploads.playable_by(actor) | ||||
|         libraries = models.Library.objects.filter( | ||||
|         qs = models.Library.objects.filter( | ||||
|             pk__in=uploads.values_list("library", flat=True) | ||||
|         ).annotate(_uploads_count=Count("uploads")) | ||||
|         libraries = libraries.select_related("actor") | ||||
|         page = self.paginate_queryset(libraries) | ||||
|         qs = qs.select_related("actor") | ||||
|         page = self.paginate_queryset(qs) | ||||
|         if page is not None: | ||||
|             serializer = federation_api_serializers.LibrarySerializer(page, many=True) | ||||
|             return self.get_paginated_response(serializer.data) | ||||
| 
 | ||||
|         serializer = federation_api_serializers.LibrarySerializer(libraries, many=True) | ||||
|         serializer = federation_api_serializers.LibrarySerializer(qs, many=True) | ||||
|         return Response(serializer.data) | ||||
| 
 | ||||
|     return view | ||||
|     return libraries | ||||
| 
 | ||||
| 
 | ||||
| class TagViewSetMixin(object): | ||||
|  | @ -73,7 +73,7 @@ class ArtistViewSet(viewsets.ReadOnlyModelViewSet): | |||
|         ) | ||||
|         return queryset.prefetch_related(Prefetch("albums", queryset=albums)) | ||||
| 
 | ||||
|     libraries = detail_route(methods=["get"])( | ||||
|     libraries = action(methods=["get"], detail=True)( | ||||
|         get_libraries( | ||||
|             filter_uploads=lambda o, uploads: uploads.filter( | ||||
|                 Q(track__artist=o) | Q(track__album__artist=o) | ||||
|  | @ -101,7 +101,7 @@ class AlbumViewSet(viewsets.ReadOnlyModelViewSet): | |||
|         qs = queryset.prefetch_related(Prefetch("tracks", queryset=tracks)) | ||||
|         return qs | ||||
| 
 | ||||
|     libraries = detail_route(methods=["get"])( | ||||
|     libraries = action(methods=["get"], detail=True)( | ||||
|         get_libraries(filter_uploads=lambda o, uploads: uploads.filter(track__album=o)) | ||||
|     ) | ||||
| 
 | ||||
|  | @ -144,7 +144,9 @@ class LibraryViewSet( | |||
|         ) | ||||
|         instance.delete() | ||||
| 
 | ||||
|     @detail_route(methods=["get"]) | ||||
|     follows = action | ||||
| 
 | ||||
|     @action(methods=["get"], detail=True) | ||||
|     @transaction.non_atomic_requests | ||||
|     def follows(self, request, *args, **kwargs): | ||||
|         library = self.get_object() | ||||
|  | @ -193,7 +195,7 @@ class TrackViewSet(TagViewSetMixin, viewsets.ReadOnlyModelViewSet): | |||
|         ) | ||||
|         return queryset | ||||
| 
 | ||||
|     @detail_route(methods=["get"]) | ||||
|     @action(methods=["get"], detail=True) | ||||
|     @transaction.non_atomic_requests | ||||
|     def lyrics(self, request, *args, **kwargs): | ||||
|         try: | ||||
|  | @ -218,7 +220,7 @@ class TrackViewSet(TagViewSetMixin, viewsets.ReadOnlyModelViewSet): | |||
|         serializer = serializers.LyricsSerializer(lyrics) | ||||
|         return Response(serializer.data) | ||||
| 
 | ||||
|     libraries = detail_route(methods=["get"])( | ||||
|     libraries = action(methods=["get"], detail=True)( | ||||
|         get_libraries(filter_uploads=lambda o, uploads: uploads.filter(track=o)) | ||||
|     ) | ||||
| 
 | ||||
|  | @ -388,7 +390,7 @@ class UploadViewSet( | |||
|         qs = super().get_queryset() | ||||
|         return qs.filter(library__actor=self.request.user.actor) | ||||
| 
 | ||||
|     @list_route(methods=["post"]) | ||||
|     @action(methods=["post"], detail=False) | ||||
|     def action(self, request, *args, **kwargs): | ||||
|         queryset = self.get_queryset() | ||||
|         serializer = serializers.UploadActionSerializer(request.data, queryset=queryset) | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| from rest_framework import viewsets | ||||
| from rest_framework.decorators import list_route | ||||
| from rest_framework.decorators import action | ||||
| from rest_framework.response import Response | ||||
| from rest_framework.views import APIView | ||||
| 
 | ||||
|  | @ -47,19 +47,19 @@ class ReleaseBrowse(APIView): | |||
| class SearchViewSet(viewsets.ViewSet): | ||||
|     permission_classes = [ConditionalAuthentication] | ||||
| 
 | ||||
|     @list_route(methods=["get"]) | ||||
|     @action(methods=["get"], detail=False) | ||||
|     def recordings(self, request, *args, **kwargs): | ||||
|         query = request.GET["query"] | ||||
|         results = api.recordings.search(query) | ||||
|         return Response(results) | ||||
| 
 | ||||
|     @list_route(methods=["get"]) | ||||
|     @action(methods=["get"], detail=False) | ||||
|     def releases(self, request, *args, **kwargs): | ||||
|         query = request.GET["query"] | ||||
|         results = api.releases.search(query) | ||||
|         return Response(results) | ||||
| 
 | ||||
|     @list_route(methods=["get"]) | ||||
|     @action(methods=["get"], detail=False) | ||||
|     def artists(self, request, *args, **kwargs): | ||||
|         query = request.GET["query"] | ||||
|         results = api.artists.search(query) | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| from django.db import transaction | ||||
| from django.db.models import Count | ||||
| from rest_framework import exceptions, mixins, viewsets | ||||
| from rest_framework.decorators import detail_route | ||||
| from rest_framework.decorators import action | ||||
| from rest_framework.permissions import IsAuthenticatedOrReadOnly | ||||
| from rest_framework.response import Response | ||||
| 
 | ||||
|  | @ -36,7 +36,7 @@ class PlaylistViewSet( | |||
|     filterset_class = filters.PlaylistFilter | ||||
|     ordering_fields = ("id", "name", "creation_date", "modification_date") | ||||
| 
 | ||||
|     @detail_route(methods=["get"]) | ||||
|     @action(methods=["get"], detail=True) | ||||
|     def tracks(self, request, *args, **kwargs): | ||||
|         playlist = self.get_object() | ||||
|         plts = playlist.playlist_tracks.all().for_nested_serialization( | ||||
|  | @ -46,7 +46,7 @@ class PlaylistViewSet( | |||
|         data = {"count": len(plts), "results": serializer.data} | ||||
|         return Response(data, status=200) | ||||
| 
 | ||||
|     @detail_route(methods=["post"]) | ||||
|     @action(methods=["post"], detail=True) | ||||
|     @transaction.atomic | ||||
|     def add(self, request, *args, **kwargs): | ||||
|         playlist = self.get_object() | ||||
|  | @ -67,7 +67,7 @@ class PlaylistViewSet( | |||
|         data = {"count": len(plts), "results": serializer.data} | ||||
|         return Response(data, status=201) | ||||
| 
 | ||||
|     @detail_route(methods=["delete"]) | ||||
|     @action(methods=["delete"], detail=True) | ||||
|     @transaction.atomic | ||||
|     def clear(self, request, *args, **kwargs): | ||||
|         playlist = self.get_object() | ||||
|  |  | |||
|  | @ -1,6 +1,6 @@ | |||
| from django.db.models import Q | ||||
| from rest_framework import mixins, permissions, status, viewsets | ||||
| from rest_framework.decorators import detail_route, list_route | ||||
| from rest_framework.decorators import action | ||||
| from rest_framework.response import Response | ||||
| 
 | ||||
| from funkwhale_api.common import permissions as common_permissions | ||||
|  | @ -40,7 +40,7 @@ class RadioViewSet( | |||
|     def perform_update(self, serializer): | ||||
|         return serializer.save(user=self.request.user) | ||||
| 
 | ||||
|     @detail_route(methods=["get"]) | ||||
|     @action(methods=["get"], detail=True) | ||||
|     def tracks(self, request, *args, **kwargs): | ||||
|         radio = self.get_object() | ||||
|         tracks = radio.get_candidates().for_nested_serialization() | ||||
|  | @ -50,14 +50,14 @@ class RadioViewSet( | |||
|             serializer = TrackSerializer(page, many=True) | ||||
|             return self.get_paginated_response(serializer.data) | ||||
| 
 | ||||
|     @list_route(methods=["get"]) | ||||
|     @action(methods=["get"], detail=False) | ||||
|     def filters(self, request, *args, **kwargs): | ||||
|         serializer = serializers.FilterSerializer( | ||||
|             filters.registry.exposed_filters, many=True | ||||
|         ) | ||||
|         return Response(serializer.data) | ||||
| 
 | ||||
|     @list_route(methods=["post"]) | ||||
|     @action(methods=["post"], detail=False) | ||||
|     def validate(self, request, *args, **kwargs): | ||||
|         try: | ||||
|             f_list = request.data["filters"] | ||||
|  |  | |||
|  | @ -1,11 +1,12 @@ | |||
| import datetime | ||||
| import functools | ||||
| 
 | ||||
| from django.conf import settings | ||||
| from django.utils import timezone | ||||
| from rest_framework import exceptions | ||||
| from rest_framework import permissions as rest_permissions | ||||
| from rest_framework import renderers, response, viewsets | ||||
| from rest_framework.decorators import list_route | ||||
| from rest_framework.decorators import action | ||||
| from rest_framework.serializers import ValidationError | ||||
| 
 | ||||
| import funkwhale_api | ||||
|  | @ -25,6 +26,7 @@ def find_object( | |||
|     queryset, model_field="pk", field="id", cast=int, filter_playable=False | ||||
| ): | ||||
|     def decorator(func): | ||||
|         @functools.wraps(func) | ||||
|         def inner(self, request, *args, **kwargs): | ||||
|             data = request.GET or request.POST | ||||
|             try: | ||||
|  | @ -110,12 +112,13 @@ class SubsonicViewSet(viewsets.GenericViewSet): | |||
| 
 | ||||
|         return response.Response(payload, status=200) | ||||
| 
 | ||||
|     @list_route(methods=["get", "post"], permission_classes=[]) | ||||
|     @action(detail=False, methods=["get", "post"], permission_classes=[]) | ||||
|     def ping(self, request, *args, **kwargs): | ||||
|         data = {"status": "ok", "version": "1.16.0"} | ||||
|         return response.Response(data, status=200) | ||||
| 
 | ||||
|     @list_route( | ||||
|     @action( | ||||
|         detail=False, | ||||
|         methods=["get", "post"], | ||||
|         url_name="get_license", | ||||
|         permissions_classes=[], | ||||
|  | @ -136,7 +139,12 @@ class SubsonicViewSet(viewsets.GenericViewSet): | |||
|         } | ||||
|         return response.Response(data, status=200) | ||||
| 
 | ||||
|     @list_route(methods=["get", "post"], url_name="get_artists", url_path="getArtists") | ||||
|     @action( | ||||
|         detail=False, | ||||
|         methods=["get", "post"], | ||||
|         url_name="get_artists", | ||||
|         url_path="getArtists", | ||||
|     ) | ||||
|     def get_artists(self, request, *args, **kwargs): | ||||
|         artists = music_models.Artist.objects.all().playable_by( | ||||
|             utils.get_actor_from_request(request) | ||||
|  | @ -146,7 +154,12 @@ class SubsonicViewSet(viewsets.GenericViewSet): | |||
| 
 | ||||
|         return response.Response(payload, status=200) | ||||
| 
 | ||||
|     @list_route(methods=["get", "post"], url_name="get_indexes", url_path="getIndexes") | ||||
|     @action( | ||||
|         detail=False, | ||||
|         methods=["get", "post"], | ||||
|         url_name="get_indexes", | ||||
|         url_path="getIndexes", | ||||
|     ) | ||||
|     def get_indexes(self, request, *args, **kwargs): | ||||
|         artists = music_models.Artist.objects.all().playable_by( | ||||
|             utils.get_actor_from_request(request) | ||||
|  | @ -156,7 +169,12 @@ class SubsonicViewSet(viewsets.GenericViewSet): | |||
| 
 | ||||
|         return response.Response(payload, status=200) | ||||
| 
 | ||||
|     @list_route(methods=["get", "post"], url_name="get_artist", url_path="getArtist") | ||||
|     @action( | ||||
|         detail=False, | ||||
|         methods=["get", "post"], | ||||
|         url_name="get_artist", | ||||
|         url_path="getArtist", | ||||
|     ) | ||||
|     @find_object(music_models.Artist.objects.all(), filter_playable=True) | ||||
|     def get_artist(self, request, *args, **kwargs): | ||||
|         artist = kwargs.pop("obj") | ||||
|  | @ -165,7 +183,9 @@ class SubsonicViewSet(viewsets.GenericViewSet): | |||
| 
 | ||||
|         return response.Response(payload, status=200) | ||||
| 
 | ||||
|     @list_route(methods=["get", "post"], url_name="get_song", url_path="getSong") | ||||
|     @action( | ||||
|         detail=False, methods=["get", "post"], url_name="get_song", url_path="getSong" | ||||
|     ) | ||||
|     @find_object(music_models.Track.objects.all(), filter_playable=True) | ||||
|     def get_song(self, request, *args, **kwargs): | ||||
|         track = kwargs.pop("obj") | ||||
|  | @ -174,8 +194,11 @@ class SubsonicViewSet(viewsets.GenericViewSet): | |||
| 
 | ||||
|         return response.Response(payload, status=200) | ||||
| 
 | ||||
|     @list_route( | ||||
|         methods=["get", "post"], url_name="get_artist_info2", url_path="getArtistInfo2" | ||||
|     @action( | ||||
|         detail=False, | ||||
|         methods=["get", "post"], | ||||
|         url_name="get_artist_info2", | ||||
|         url_path="getArtistInfo2", | ||||
|     ) | ||||
|     @find_object(music_models.Artist.objects.all(), filter_playable=True) | ||||
|     def get_artist_info2(self, request, *args, **kwargs): | ||||
|  | @ -183,7 +206,9 @@ class SubsonicViewSet(viewsets.GenericViewSet): | |||
| 
 | ||||
|         return response.Response(payload, status=200) | ||||
| 
 | ||||
|     @list_route(methods=["get", "post"], url_name="get_album", url_path="getAlbum") | ||||
|     @action( | ||||
|         detail=False, methods=["get", "post"], url_name="get_album", url_path="getAlbum" | ||||
|     ) | ||||
|     @find_object( | ||||
|         music_models.Album.objects.select_related("artist"), filter_playable=True | ||||
|     ) | ||||
|  | @ -193,7 +218,7 @@ class SubsonicViewSet(viewsets.GenericViewSet): | |||
|         payload = {"album": data} | ||||
|         return response.Response(payload, status=200) | ||||
| 
 | ||||
|     @list_route(methods=["get", "post"], url_name="stream", url_path="stream") | ||||
|     @action(detail=False, methods=["get", "post"], url_name="stream", url_path="stream") | ||||
|     @find_object(music_models.Track.objects.all(), filter_playable=True) | ||||
|     def stream(self, request, *args, **kwargs): | ||||
|         data = request.GET or request.POST | ||||
|  | @ -208,30 +233,36 @@ class SubsonicViewSet(viewsets.GenericViewSet): | |||
|             format = None | ||||
|         return music_views.handle_serve(upload=upload, user=request.user, format=format) | ||||
| 
 | ||||
|     @list_route(methods=["get", "post"], url_name="star", url_path="star") | ||||
|     @action(detail=False, methods=["get", "post"], url_name="star", url_path="star") | ||||
|     @find_object(music_models.Track.objects.all()) | ||||
|     def star(self, request, *args, **kwargs): | ||||
|         track = kwargs.pop("obj") | ||||
|         TrackFavorite.add(user=request.user, track=track) | ||||
|         return response.Response({"status": "ok"}) | ||||
| 
 | ||||
|     @list_route(methods=["get", "post"], url_name="unstar", url_path="unstar") | ||||
|     @action(detail=False, methods=["get", "post"], url_name="unstar", url_path="unstar") | ||||
|     @find_object(music_models.Track.objects.all()) | ||||
|     def unstar(self, request, *args, **kwargs): | ||||
|         track = kwargs.pop("obj") | ||||
|         request.user.track_favorites.filter(track=track).delete() | ||||
|         return response.Response({"status": "ok"}) | ||||
| 
 | ||||
|     @list_route( | ||||
|         methods=["get", "post"], url_name="get_starred2", url_path="getStarred2" | ||||
|     @action( | ||||
|         detail=False, | ||||
|         methods=["get", "post"], | ||||
|         url_name="get_starred2", | ||||
|         url_path="getStarred2", | ||||
|     ) | ||||
|     def get_starred2(self, request, *args, **kwargs): | ||||
|         favorites = request.user.track_favorites.all() | ||||
|         data = {"starred2": {"song": serializers.get_starred_tracks_data(favorites)}} | ||||
|         return response.Response(data) | ||||
| 
 | ||||
|     @list_route( | ||||
|         methods=["get", "post"], url_name="get_random_songs", url_path="getRandomSongs" | ||||
|     @action( | ||||
|         detail=False, | ||||
|         methods=["get", "post"], | ||||
|         url_name="get_random_songs", | ||||
|         url_path="getRandomSongs", | ||||
|     ) | ||||
|     def get_random_songs(self, request, *args, **kwargs): | ||||
|         data = request.GET or request.POST | ||||
|  | @ -253,14 +284,22 @@ class SubsonicViewSet(viewsets.GenericViewSet): | |||
|         } | ||||
|         return response.Response(data) | ||||
| 
 | ||||
|     @list_route(methods=["get", "post"], url_name="get_starred", url_path="getStarred") | ||||
|     @action( | ||||
|         detail=False, | ||||
|         methods=["get", "post"], | ||||
|         url_name="get_starred", | ||||
|         url_path="getStarred", | ||||
|     ) | ||||
|     def get_starred(self, request, *args, **kwargs): | ||||
|         favorites = request.user.track_favorites.all() | ||||
|         data = {"starred": {"song": serializers.get_starred_tracks_data(favorites)}} | ||||
|         return response.Response(data) | ||||
| 
 | ||||
|     @list_route( | ||||
|         methods=["get", "post"], url_name="get_album_list2", url_path="getAlbumList2" | ||||
|     @action( | ||||
|         detail=False, | ||||
|         methods=["get", "post"], | ||||
|         url_name="get_album_list2", | ||||
|         url_path="getAlbumList2", | ||||
|     ) | ||||
|     def get_album_list2(self, request, *args, **kwargs): | ||||
|         queryset = music_models.Album.objects.with_tracks_count().order_by( | ||||
|  | @ -287,7 +326,9 @@ class SubsonicViewSet(viewsets.GenericViewSet): | |||
|         data = {"albumList2": {"album": serializers.get_album_list2_data(queryset)}} | ||||
|         return response.Response(data) | ||||
| 
 | ||||
|     @list_route(methods=["get", "post"], url_name="search3", url_path="search3") | ||||
|     @action( | ||||
|         detail=False, methods=["get", "post"], url_name="search3", url_path="search3" | ||||
|     ) | ||||
|     def search3(self, request, *args, **kwargs): | ||||
|         data = request.GET or request.POST | ||||
|         query = str(data.get("query", "")).replace("*", "") | ||||
|  | @ -350,8 +391,11 @@ class SubsonicViewSet(viewsets.GenericViewSet): | |||
|             payload["searchResult3"][c["subsonic"]] = c["serializer"](queryset) | ||||
|         return response.Response(payload) | ||||
| 
 | ||||
|     @list_route( | ||||
|         methods=["get", "post"], url_name="get_playlists", url_path="getPlaylists" | ||||
|     @action( | ||||
|         detail=False, | ||||
|         methods=["get", "post"], | ||||
|         url_name="get_playlists", | ||||
|         url_path="getPlaylists", | ||||
|     ) | ||||
|     def get_playlists(self, request, *args, **kwargs): | ||||
|         playlists = request.user.playlists.with_tracks_count().select_related("user") | ||||
|  | @ -362,8 +406,11 @@ class SubsonicViewSet(viewsets.GenericViewSet): | |||
|         } | ||||
|         return response.Response(data) | ||||
| 
 | ||||
|     @list_route( | ||||
|         methods=["get", "post"], url_name="get_playlist", url_path="getPlaylist" | ||||
|     @action( | ||||
|         detail=False, | ||||
|         methods=["get", "post"], | ||||
|         url_name="get_playlist", | ||||
|         url_path="getPlaylist", | ||||
|     ) | ||||
|     @find_object(playlists_models.Playlist.objects.with_tracks_count()) | ||||
|     def get_playlist(self, request, *args, **kwargs): | ||||
|  | @ -371,8 +418,11 @@ class SubsonicViewSet(viewsets.GenericViewSet): | |||
|         data = {"playlist": serializers.get_playlist_detail_data(playlist)} | ||||
|         return response.Response(data) | ||||
| 
 | ||||
|     @list_route( | ||||
|         methods=["get", "post"], url_name="update_playlist", url_path="updatePlaylist" | ||||
|     @action( | ||||
|         detail=False, | ||||
|         methods=["get", "post"], | ||||
|         url_name="update_playlist", | ||||
|         url_path="updatePlaylist", | ||||
|     ) | ||||
|     @find_object(lambda request: request.user.playlists.all(), field="playlistId") | ||||
|     def update_playlist(self, request, *args, **kwargs): | ||||
|  | @ -413,8 +463,11 @@ class SubsonicViewSet(viewsets.GenericViewSet): | |||
|         data = {"status": "ok"} | ||||
|         return response.Response(data) | ||||
| 
 | ||||
|     @list_route( | ||||
|         methods=["get", "post"], url_name="delete_playlist", url_path="deletePlaylist" | ||||
|     @action( | ||||
|         detail=False, | ||||
|         methods=["get", "post"], | ||||
|         url_name="delete_playlist", | ||||
|         url_path="deletePlaylist", | ||||
|     ) | ||||
|     @find_object(lambda request: request.user.playlists.all()) | ||||
|     def delete_playlist(self, request, *args, **kwargs): | ||||
|  | @ -423,8 +476,11 @@ class SubsonicViewSet(viewsets.GenericViewSet): | |||
|         data = {"status": "ok"} | ||||
|         return response.Response(data) | ||||
| 
 | ||||
|     @list_route( | ||||
|         methods=["get", "post"], url_name="create_playlist", url_path="createPlaylist" | ||||
|     @action( | ||||
|         detail=False, | ||||
|         methods=["get", "post"], | ||||
|         url_name="create_playlist", | ||||
|         url_path="createPlaylist", | ||||
|     ) | ||||
|     def create_playlist(self, request, *args, **kwargs): | ||||
|         data = request.GET or request.POST | ||||
|  | @ -462,7 +518,12 @@ class SubsonicViewSet(viewsets.GenericViewSet): | |||
|         data = {"playlist": serializers.get_playlist_detail_data(playlist)} | ||||
|         return response.Response(data) | ||||
| 
 | ||||
|     @list_route(methods=["get", "post"], url_name="get_avatar", url_path="getAvatar") | ||||
|     @action( | ||||
|         detail=False, | ||||
|         methods=["get", "post"], | ||||
|         url_name="get_avatar", | ||||
|         url_path="getAvatar", | ||||
|     ) | ||||
|     @find_object( | ||||
|         queryset=users_models.User.objects.exclude(avatar=None).exclude(avatar=""), | ||||
|         model_field="username__iexact", | ||||
|  | @ -479,7 +540,9 @@ class SubsonicViewSet(viewsets.GenericViewSet): | |||
|         r[file_header] = path | ||||
|         return r | ||||
| 
 | ||||
|     @list_route(methods=["get", "post"], url_name="get_user", url_path="getUser") | ||||
|     @action( | ||||
|         detail=False, methods=["get", "post"], url_name="get_user", url_path="getUser" | ||||
|     ) | ||||
|     @find_object( | ||||
|         queryset=lambda request: users_models.User.objects.filter(pk=request.user.pk), | ||||
|         model_field="username__iexact", | ||||
|  | @ -490,7 +553,8 @@ class SubsonicViewSet(viewsets.GenericViewSet): | |||
|         data = {"user": serializers.get_user_detail_data(request.user)} | ||||
|         return response.Response(data) | ||||
| 
 | ||||
|     @list_route( | ||||
|     @action( | ||||
|         detail=False, | ||||
|         methods=["get", "post"], | ||||
|         url_name="get_music_folders", | ||||
|         url_path="getMusicFolders", | ||||
|  | @ -499,8 +563,11 @@ class SubsonicViewSet(viewsets.GenericViewSet): | |||
|         data = {"musicFolders": {"musicFolder": [{"id": 1, "name": "Music"}]}} | ||||
|         return response.Response(data) | ||||
| 
 | ||||
|     @list_route( | ||||
|         methods=["get", "post"], url_name="get_cover_art", url_path="getCoverArt" | ||||
|     @action( | ||||
|         detail=False, | ||||
|         methods=["get", "post"], | ||||
|         url_name="get_cover_art", | ||||
|         url_path="getCoverArt", | ||||
|     ) | ||||
|     def get_cover_art(self, request, *args, **kwargs): | ||||
|         data = request.GET or request.POST | ||||
|  | @ -536,7 +603,9 @@ class SubsonicViewSet(viewsets.GenericViewSet): | |||
|         r[file_header] = path | ||||
|         return r | ||||
| 
 | ||||
|     @list_route(methods=["get", "post"], url_name="scrobble", url_path="scrobble") | ||||
|     @action( | ||||
|         detail=False, methods=["get", "post"], url_name="scrobble", url_path="scrobble" | ||||
|     ) | ||||
|     def scrobble(self, request, *args, **kwargs): | ||||
|         data = request.GET or request.POST | ||||
|         serializer = serializers.ScrobbleSerializer( | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| from allauth.account.adapter import get_adapter | ||||
| from rest_auth.registration.views import RegisterView as BaseRegisterView | ||||
| from rest_framework import mixins, viewsets | ||||
| from rest_framework.decorators import detail_route, list_route | ||||
| from rest_framework.decorators import action | ||||
| from rest_framework.response import Response | ||||
| 
 | ||||
| from funkwhale_api.common import preferences | ||||
|  | @ -28,13 +28,13 @@ class UserViewSet(mixins.UpdateModelMixin, viewsets.GenericViewSet): | |||
|     serializer_class = serializers.UserWriteSerializer | ||||
|     lookup_field = "username" | ||||
| 
 | ||||
|     @list_route(methods=["get"]) | ||||
|     @action(methods=["get"], detail=False) | ||||
|     def me(self, request, *args, **kwargs): | ||||
|         """Return information about the current user""" | ||||
|         serializer = serializers.MeSerializer(request.user) | ||||
|         return Response(serializer.data) | ||||
| 
 | ||||
|     @detail_route(methods=["get", "post", "delete"], url_path="subsonic-token") | ||||
|     @action(methods=["get", "post", "delete"], url_path="subsonic-token", detail=True) | ||||
|     def subsonic_token(self, request, *args, **kwargs): | ||||
|         if not self.request.user.username == kwargs.get("username"): | ||||
|             return Response(status=403) | ||||
|  |  | |||
|  | @ -30,7 +30,7 @@ celery>=4.1,<4.2 | |||
| # Your custom requirements go here | ||||
| django-cors-headers>=2.1,<2.2 | ||||
| musicbrainzngs==0.6 | ||||
| djangorestframework>=3.7,<3.8 | ||||
| djangorestframework>=3.9,<3.10 | ||||
| djangorestframework-jwt>=1.11,<1.12 | ||||
| oauth2client<4 | ||||
| pendulum>=2,<3 | ||||
|  |  | |||
|  | @ -45,7 +45,7 @@ def test_exception_wrong_credentials(f, db, api_client): | |||
| 
 | ||||
| @pytest.mark.parametrize("f", ["json"]) | ||||
| def test_exception_missing_credentials(f, db, api_client): | ||||
|     url = reverse("api:subsonic-get-artists") | ||||
|     url = reverse("api:subsonic-get_artists") | ||||
|     response = api_client.get(url) | ||||
| 
 | ||||
|     expected = { | ||||
|  | @ -66,7 +66,7 @@ def test_disabled_subsonic(preferences, api_client): | |||
| 
 | ||||
| @pytest.mark.parametrize("f", ["xml", "json"]) | ||||
| def test_get_license(f, db, logged_in_api_client, mocker): | ||||
|     url = reverse("api:subsonic-get-license") | ||||
|     url = reverse("api:subsonic-get_license") | ||||
|     assert url.endswith("getLicense") is True | ||||
|     now = timezone.now() | ||||
|     mocker.patch("django.utils.timezone.now", return_value=now) | ||||
|  | @ -100,7 +100,7 @@ def test_ping(f, db, api_client): | |||
| def test_get_artists( | ||||
|     f, db, logged_in_api_client, factories, mocker, queryset_equal_queries | ||||
| ): | ||||
|     url = reverse("api:subsonic-get-artists") | ||||
|     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") | ||||
|  | @ -120,7 +120,7 @@ def test_get_artists( | |||
| def test_get_artist( | ||||
|     f, db, logged_in_api_client, factories, mocker, queryset_equal_queries | ||||
| ): | ||||
|     url = reverse("api:subsonic-get-artist") | ||||
|     url = reverse("api:subsonic-get_artist") | ||||
|     assert url.endswith("getArtist") is True | ||||
|     artist = factories["music.Artist"](playable=True) | ||||
|     factories["music.Album"].create_batch(size=3, artist=artist, playable=True) | ||||
|  | @ -136,7 +136,7 @@ def test_get_artist( | |||
| 
 | ||||
| @pytest.mark.parametrize("f", ["json"]) | ||||
| def test_get_invalid_artist(f, db, logged_in_api_client, factories): | ||||
|     url = reverse("api:subsonic-get-artist") | ||||
|     url = reverse("api:subsonic-get_artist") | ||||
|     assert url.endswith("getArtist") is True | ||||
|     expected = {"error": {"code": 0, "message": 'For input string "asdf"'}} | ||||
|     response = logged_in_api_client.get(url, {"id": "asdf"}) | ||||
|  | @ -149,7 +149,7 @@ def test_get_invalid_artist(f, db, logged_in_api_client, factories): | |||
| def test_get_artist_info2( | ||||
|     f, db, logged_in_api_client, factories, mocker, queryset_equal_queries | ||||
| ): | ||||
|     url = reverse("api:subsonic-get-artist-info2") | ||||
|     url = reverse("api:subsonic-get_artist_info2") | ||||
|     assert url.endswith("getArtistInfo2") is True | ||||
|     artist = factories["music.Artist"](playable=True) | ||||
|     playable_by = mocker.spy(music_models.ArtistQuerySet, "playable_by") | ||||
|  | @ -167,7 +167,7 @@ def test_get_artist_info2( | |||
| def test_get_album( | ||||
|     f, db, logged_in_api_client, factories, mocker, queryset_equal_queries | ||||
| ): | ||||
|     url = reverse("api:subsonic-get-album") | ||||
|     url = reverse("api:subsonic-get_album") | ||||
|     assert url.endswith("getAlbum") is True | ||||
|     artist = factories["music.Artist"]() | ||||
|     album = factories["music.Album"](artist=artist) | ||||
|  | @ -188,7 +188,7 @@ def test_get_album( | |||
| def test_get_song( | ||||
|     f, db, logged_in_api_client, factories, mocker, queryset_equal_queries | ||||
| ): | ||||
|     url = reverse("api:subsonic-get-song") | ||||
|     url = reverse("api:subsonic-get_song") | ||||
|     assert url.endswith("getSong") is True | ||||
|     artist = factories["music.Artist"]() | ||||
|     album = factories["music.Album"](artist=artist) | ||||
|  | @ -264,7 +264,7 @@ def test_unstar(f, db, logged_in_api_client, factories): | |||
| 
 | ||||
| @pytest.mark.parametrize("f", ["json"]) | ||||
| def test_get_starred2(f, db, logged_in_api_client, factories): | ||||
|     url = reverse("api:subsonic-get-starred2") | ||||
|     url = reverse("api:subsonic-get_starred2") | ||||
|     assert url.endswith("getStarred2") is True | ||||
|     track = factories["music.Track"]() | ||||
|     favorite = factories["favorites.TrackFavorite"]( | ||||
|  | @ -280,7 +280,7 @@ def test_get_starred2(f, db, logged_in_api_client, factories): | |||
| 
 | ||||
| @pytest.mark.parametrize("f", ["json"]) | ||||
| def test_get_random_songs(f, db, logged_in_api_client, factories, mocker): | ||||
|     url = reverse("api:subsonic-get-random-songs") | ||||
|     url = reverse("api:subsonic-get_random_songs") | ||||
|     assert url.endswith("getRandomSongs") is True | ||||
|     track1 = factories["music.Track"]() | ||||
|     track2 = factories["music.Track"]() | ||||
|  | @ -303,7 +303,7 @@ def test_get_random_songs(f, db, logged_in_api_client, factories, mocker): | |||
| 
 | ||||
| @pytest.mark.parametrize("f", ["json"]) | ||||
| def test_get_starred(f, db, logged_in_api_client, factories): | ||||
|     url = reverse("api:subsonic-get-starred") | ||||
|     url = reverse("api:subsonic-get_starred") | ||||
|     assert url.endswith("getStarred") is True | ||||
|     track = factories["music.Track"]() | ||||
|     favorite = factories["favorites.TrackFavorite"]( | ||||
|  | @ -321,7 +321,7 @@ def test_get_starred(f, db, logged_in_api_client, factories): | |||
| def test_get_album_list2( | ||||
|     f, db, logged_in_api_client, factories, mocker, queryset_equal_queries | ||||
| ): | ||||
|     url = reverse("api:subsonic-get-album-list2") | ||||
|     url = reverse("api:subsonic-get_album_list2") | ||||
|     assert url.endswith("getAlbumList2") is True | ||||
|     album1 = factories["music.Album"](playable=True) | ||||
|     album2 = factories["music.Album"](playable=True) | ||||
|  | @ -338,7 +338,7 @@ def test_get_album_list2( | |||
| 
 | ||||
| @pytest.mark.parametrize("f", ["json"]) | ||||
| def test_get_album_list2_pagination(f, db, logged_in_api_client, factories): | ||||
|     url = reverse("api:subsonic-get-album-list2") | ||||
|     url = reverse("api:subsonic-get_album_list2") | ||||
|     assert url.endswith("getAlbumList2") is True | ||||
|     album1 = factories["music.Album"](playable=True) | ||||
|     factories["music.Album"](playable=True) | ||||
|  | @ -385,7 +385,7 @@ def test_search3(f, db, logged_in_api_client, factories): | |||
| 
 | ||||
| @pytest.mark.parametrize("f", ["json"]) | ||||
| def test_get_playlists(f, db, logged_in_api_client, factories): | ||||
|     url = reverse("api:subsonic-get-playlists") | ||||
|     url = reverse("api:subsonic-get_playlists") | ||||
|     assert url.endswith("getPlaylists") is True | ||||
|     playlist = factories["playlists.Playlist"](user=logged_in_api_client.user) | ||||
|     response = logged_in_api_client.get(url, {"f": f}) | ||||
|  | @ -399,7 +399,7 @@ def test_get_playlists(f, db, logged_in_api_client, factories): | |||
| 
 | ||||
| @pytest.mark.parametrize("f", ["json"]) | ||||
| def test_get_playlist(f, db, logged_in_api_client, factories): | ||||
|     url = reverse("api:subsonic-get-playlist") | ||||
|     url = reverse("api:subsonic-get_playlist") | ||||
|     assert url.endswith("getPlaylist") is True | ||||
|     playlist = factories["playlists.Playlist"](user=logged_in_api_client.user) | ||||
|     response = logged_in_api_client.get(url, {"f": f, "id": playlist.pk}) | ||||
|  | @ -413,7 +413,7 @@ def test_get_playlist(f, db, logged_in_api_client, factories): | |||
| 
 | ||||
| @pytest.mark.parametrize("f", ["json"]) | ||||
| def test_update_playlist(f, db, logged_in_api_client, factories): | ||||
|     url = reverse("api:subsonic-update-playlist") | ||||
|     url = reverse("api:subsonic-update_playlist") | ||||
|     assert url.endswith("updatePlaylist") is True | ||||
|     playlist = factories["playlists.Playlist"](user=logged_in_api_client.user) | ||||
|     factories["playlists.PlaylistTrack"](index=0, playlist=playlist) | ||||
|  | @ -437,7 +437,7 @@ def test_update_playlist(f, db, logged_in_api_client, factories): | |||
| 
 | ||||
| @pytest.mark.parametrize("f", ["json"]) | ||||
| def test_delete_playlist(f, db, logged_in_api_client, factories): | ||||
|     url = reverse("api:subsonic-delete-playlist") | ||||
|     url = reverse("api:subsonic-delete_playlist") | ||||
|     assert url.endswith("deletePlaylist") is True | ||||
|     playlist = factories["playlists.Playlist"](user=logged_in_api_client.user) | ||||
|     response = logged_in_api_client.get(url, {"f": f, "id": playlist.pk}) | ||||
|  | @ -448,7 +448,7 @@ def test_delete_playlist(f, db, logged_in_api_client, factories): | |||
| 
 | ||||
| @pytest.mark.parametrize("f", ["json"]) | ||||
| def test_create_playlist(f, db, logged_in_api_client, factories): | ||||
|     url = reverse("api:subsonic-create-playlist") | ||||
|     url = reverse("api:subsonic-create_playlist") | ||||
|     assert url.endswith("createPlaylist") is True | ||||
|     track1 = factories["music.Track"]() | ||||
|     track2 = factories["music.Track"]() | ||||
|  | @ -470,7 +470,7 @@ def test_create_playlist(f, db, logged_in_api_client, factories): | |||
| 
 | ||||
| @pytest.mark.parametrize("f", ["json"]) | ||||
| def test_get_music_folders(f, db, logged_in_api_client, factories): | ||||
|     url = reverse("api:subsonic-get-music-folders") | ||||
|     url = reverse("api:subsonic-get_music_folders") | ||||
|     assert url.endswith("getMusicFolders") is True | ||||
|     response = logged_in_api_client.get(url, {"f": f}) | ||||
|     assert response.status_code == 200 | ||||
|  | @ -483,7 +483,7 @@ 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 | ||||
| ): | ||||
|     url = reverse("api:subsonic-get-indexes") | ||||
|     url = reverse("api:subsonic-get_indexes") | ||||
|     assert url.endswith("getIndexes") is True | ||||
|     factories["music.Artist"].create_batch(size=3, playable=True) | ||||
|     expected = { | ||||
|  | @ -501,7 +501,7 @@ def test_get_indexes( | |||
| 
 | ||||
| 
 | ||||
| def test_get_cover_art_album(factories, logged_in_api_client): | ||||
|     url = reverse("api:subsonic-get-cover-art") | ||||
|     url = reverse("api:subsonic-get_cover_art") | ||||
|     assert url.endswith("getCoverArt") is True | ||||
|     album = factories["music.Album"]() | ||||
|     response = logged_in_api_client.get(url, {"id": "al-{}".format(album.pk)}) | ||||
|  | @ -515,7 +515,7 @@ def test_get_cover_art_album(factories, logged_in_api_client): | |||
| 
 | ||||
| def test_get_avatar(factories, logged_in_api_client): | ||||
|     user = factories["users.User"]() | ||||
|     url = reverse("api:subsonic-get-avatar") | ||||
|     url = reverse("api:subsonic-get_avatar") | ||||
|     assert url.endswith("getAvatar") is True | ||||
|     response = logged_in_api_client.get(url, {"username": user.username}) | ||||
| 
 | ||||
|  | @ -541,7 +541,7 @@ def test_scrobble(factories, logged_in_api_client): | |||
| 
 | ||||
| @pytest.mark.parametrize("f", ["json"]) | ||||
| def test_get_user(f, db, logged_in_api_client, factories): | ||||
|     url = reverse("api:subsonic-get-user") | ||||
|     url = reverse("api:subsonic-get_user") | ||||
|     assert url.endswith("getUser") is True | ||||
|     response = logged_in_api_client.get( | ||||
|         url, {"f": f, "username": logged_in_api_client.user.username} | ||||
|  |  | |||
		Ładowanie…
	
		Reference in New Issue
	
	 Eliot Berriot
						Eliot Berriot