See #170: can now subscribe/unsubscribe to channel

merge-requests/1042/head
Eliot Berriot 2020-01-15 14:24:22 +01:00
rodzic fc850e6e5d
commit 4236cc6274
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 6B501DFD73514E14
5 zmienionych plików z 104 dodań i 1 usunięć

Wyświetl plik

@ -33,3 +33,14 @@ class ChannelFactory(NoUpdateOnCreate, factory.django.DjangoModelFactory):
),
artist__local=True,
)
@registry.register(name="audio.Subscription")
class SubscriptionFactory(NoUpdateOnCreate, factory.django.DjangoModelFactory):
uuid = factory.Faker("uuid4")
approved = True
target = factory.LazyAttribute(lambda o: ChannelFactory().actor)
actor = factory.SubFactory(federation_factories.ActorFactory)
class Meta:
model = "federation.Follow"

Wyświetl plik

@ -96,3 +96,15 @@ class ChannelSerializer(serializers.ModelSerializer):
def get_artist(self, obj):
return music_serializers.serialize_artist_simple(obj.artist)
class SubscriptionSerializer(serializers.Serializer):
approved = serializers.BooleanField(read_only=True)
fid = serializers.URLField(read_only=True)
uuid = serializers.UUIDField(read_only=True)
creation_date = serializers.DateTimeField(read_only=True)
def to_representation(self, obj):
data = super().to_representation(obj)
data["channel"] = ChannelSerializer(obj.target.channel).data
return data

Wyświetl plik

@ -1,6 +1,12 @@
from rest_framework import exceptions, mixins, viewsets
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
from django import http
from django.db.utils import IntegrityError
from funkwhale_api.common import permissions
from funkwhale_api.common import preferences
@ -52,3 +58,33 @@ class ChannelViewSet(
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()
try:
subscription = object.actor.received_follows.create(
approved=True, actor=request.user.actor,
)
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)

Wyświetl plik

@ -88,3 +88,16 @@ def test_channel_serializer_representation(factories, to_api_date):
).data
assert serializers.ChannelSerializer(channel).data == expected
def test_subscription_serializer(factories, to_api_date):
subscription = factories["audio.Subscription"]()
expected = {
"channel": serializers.ChannelSerializer(subscription.target.channel).data,
"uuid": str(subscription.uuid),
"creation_date": to_api_date(subscription.creation_date),
"approved": subscription.approved,
"fid": subscription.fid,
}
assert serializers.SubscriptionSerializer(subscription).data == expected

Wyświetl plik

@ -126,3 +126,34 @@ def test_channel_views_disabled_via_feature_flag(
url = reverse(url_name)
response = logged_in_api_client.get(url)
assert response.status_code == 405
def test_channel_subscribe(factories, logged_in_api_client):
actor = logged_in_api_client.user.create_actor()
channel = factories["audio.Channel"](artist__description=None)
url = reverse("api:v1:channels-subscribe", kwargs={"uuid": channel.uuid})
response = logged_in_api_client.post(url)
assert response.status_code == 201
subscription = actor.emitted_follows.select_related(
"target__channel__artist__description"
).latest("id")
expected = serializers.SubscriptionSerializer(subscription).data
assert response.data == expected
assert subscription.target == channel.actor
def test_channel_unsubscribe(factories, logged_in_api_client):
actor = logged_in_api_client.user.create_actor()
channel = factories["audio.Channel"]()
subscription = factories["audio.Subscription"](target=channel.actor, actor=actor)
url = reverse("api:v1:channels-unsubscribe", kwargs={"uuid": channel.uuid})
response = logged_in_api_client.post(url)
assert response.status_code == 204
with pytest.raises(subscription.DoesNotExist):
subscription.refresh_from_db()