Newer
Older
from rest_framework import decorators
from rest_framework import exceptions
from rest_framework import mixins
from rest_framework import permissions as rest_permissions
from rest_framework import response
from rest_framework import viewsets
Eliot Berriot
committed
from django import http
from django.db.utils import IntegrityError
Eliot Berriot
committed
from funkwhale_api.common import permissions
from funkwhale_api.common import preferences
from funkwhale_api.federation import models as federation_models
Eliot Berriot
committed
from funkwhale_api.users.oauth import permissions as oauth_permissions
from . import filters, models, serializers
class ChannelsMixin(object):
def dispatch(self, request, *args, **kwargs):
if not preferences.get("audio__channels_enabled"):
return http.HttpResponse(status=405)
return super().dispatch(request, *args, **kwargs)
class ChannelViewSet(
ChannelsMixin,
mixins.CreateModelMixin,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.ListModelMixin,
mixins.DestroyModelMixin,
viewsets.GenericViewSet,
):
lookup_field = "uuid"
filterset_class = filters.ChannelFilter
serializer_class = serializers.ChannelSerializer
queryset = (
models.Channel.objects.all()
.prefetch_related("library", "attributed_to", "artist__description", "actor")
Eliot Berriot
committed
.order_by("-creation_date")
)
permission_classes = [
oauth_permissions.ScopePermission,
permissions.OwnerPermission,
]
required_scope = "libraries"
anonymous_policy = "setting"
owner_checks = ["write"]
owner_field = "attributed_to.user"
owner_exception = exceptions.PermissionDenied
def get_serializer_class(self):
if self.request.method.lower() in ["head", "get", "options"]:
return serializers.ChannelSerializer
elif self.action in ["update", "partial_update"]:
return serializers.ChannelUpdateSerializer
return serializers.ChannelCreateSerializer
def perform_create(self, serializer):
return serializer.save(attributed_to=self.request.user.actor)
@decorators.action(
detail=True,
methods=["post"],
permission_classes=[rest_permissions.IsAuthenticated],
)
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()
subscription.save()
except IntegrityError:
# there's already a subscription for this actor/channel
subscription = object.actor.received_follows.filter(
actor=request.user.actor
).get()
data = serializers.SubscriptionSerializer(subscription).data
return response.Response(data, status=201)
@decorators.action(
detail=True,
methods=["post", "delete"],
permission_classes=[rest_permissions.IsAuthenticated],
)
def unsubscribe(self, request, *args, **kwargs):
object = self.get_object()
request.user.actor.emitted_follows.filter(target=object.actor).delete()
return response.Response(status=204)
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
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)