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

Merge branch '170-subscriptions-api-list' into 'develop'

See #170: added missing /api/v1/subscriptions endpoint

See merge request funkwhale/funkwhale!996
parents 59e3650f 959faf25
No related branches found
No related tags found
No related merge requests found
......@@ -23,6 +23,7 @@ router.register(r"libraries", views.LibraryViewSet, "libraries")
router.register(r"listen", views.ListenViewSet, "listen")
router.register(r"artists", views.ArtistViewSet, "artists")
router.register(r"channels", audio_views.ChannelViewSet, "channels")
router.register(r"subscriptions", audio_views.SubscriptionsViewSet, "subscriptions")
router.register(r"albums", views.AlbumViewSet, "albums")
router.register(r"licenses", views.LicenseViewSet, "licenses")
router.register(r"playlists", playlists_views.PlaylistViewSet, "playlists")
......
......@@ -10,6 +10,7 @@ from django.db.utils import IntegrityError
from funkwhale_api.common import permissions
from funkwhale_api.common import preferences
from funkwhale_api.federation import models as federation_models
from funkwhale_api.users.oauth import permissions as oauth_permissions
from . import filters, models, serializers
......@@ -66,10 +67,12 @@ class ChannelViewSet(
)
def subscribe(self, request, *args, **kwargs):
object = self.get_object()
subscription = federation_models.Follow(
target=object.actor, approved=True, actor=request.user.actor,
)
subscription.fid = subscription.get_federation_id()
try:
subscription = object.actor.received_follows.create(
approved=True, actor=request.user.actor,
)
subscription.save()
except IntegrityError:
# there's already a subscription for this actor/channel
subscription = object.actor.received_follows.filter(
......@@ -88,3 +91,48 @@ class ChannelViewSet(
object = self.get_object()
request.user.actor.emitted_follows.filter(target=object.actor).delete()
return response.Response(status=204)
class SubscriptionsViewSet(
ChannelsMixin,
mixins.RetrieveModelMixin,
mixins.ListModelMixin,
viewsets.GenericViewSet,
):
lookup_field = "uuid"
serializer_class = serializers.SubscriptionSerializer
queryset = (
federation_models.Follow.objects.exclude(target__channel__isnull=True)
.prefetch_related(
"target__channel__library",
"target__channel__attributed_to",
"target__channel__artist__description",
"actor",
)
.order_by("-creation_date")
)
permission_classes = [
oauth_permissions.ScopePermission,
rest_permissions.IsAuthenticated,
]
required_scope = "libraries"
anonymous_policy = False
def get_queryset(self):
qs = super().get_queryset()
return qs.filter(actor=self.request.user.actor)
@decorators.action(methods=["get"], detail=False)
def all(self, request, *args, **kwargs):
"""
Return all the subscriptions of the current user, with only limited data
to have a performant endpoint and avoid lots of queries just to display
subscription status in the UI
"""
subscriptions = list(self.get_queryset().values_list("uuid", flat=True))
payload = {
"results": [str(u) for u in subscriptions],
"count": len(subscriptions),
}
return response.Response(payload, status=200)
......@@ -140,6 +140,7 @@ def test_channel_subscribe(factories, logged_in_api_client):
subscription = actor.emitted_follows.select_related(
"target__channel__artist__description"
).latest("id")
assert subscription.fid == subscription.get_federation_id()
expected = serializers.SubscriptionSerializer(subscription).data
assert response.data == expected
assert subscription.target == channel.actor
......@@ -157,3 +158,34 @@ def test_channel_unsubscribe(factories, logged_in_api_client):
with pytest.raises(subscription.DoesNotExist):
subscription.refresh_from_db()
def test_subscriptions_list(factories, logged_in_api_client):
actor = logged_in_api_client.user.create_actor()
channel = factories["audio.Channel"](artist__description=None)
subscription = factories["audio.Subscription"](target=channel.actor, actor=actor)
factories["audio.Subscription"](target=channel.actor)
url = reverse("api:v1:subscriptions-list")
expected = serializers.SubscriptionSerializer(subscription).data
response = logged_in_api_client.get(url)
assert response.status_code == 200
assert response.data["results"][0] == expected
assert response.data == {
"results": [expected],
"count": 1,
"next": None,
"previous": None,
}
def test_subscriptions_all(factories, logged_in_api_client):
actor = logged_in_api_client.user.create_actor()
channel = factories["audio.Channel"](artist__description=None)
subscription = factories["audio.Subscription"](target=channel.actor, actor=actor)
factories["audio.Subscription"](target=channel.actor)
url = reverse("api:v1:subscriptions-all")
response = logged_in_api_client.get(url)
assert response.status_code == 200
assert response.data == {"results": [subscription.uuid], "count": 1}
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