See #170: support for auth in RSS feed

This commit is contained in:
Eliot Berriot 2020-02-14 16:28:58 +01:00
parent 27ada7845c
commit dfa8b67590
2 changed files with 46 additions and 4 deletions

View File

@ -6,12 +6,14 @@ from rest_framework import response
from rest_framework import viewsets from rest_framework import viewsets
from django import http from django import http
from django.db import transaction
from django.db.models import Count, Prefetch from django.db.models import Count, Prefetch
from django.db.utils import IntegrityError from django.db.utils import IntegrityError
from funkwhale_api.common import permissions from funkwhale_api.common import permissions
from funkwhale_api.common import preferences from funkwhale_api.common import preferences
from funkwhale_api.federation import models as federation_models from funkwhale_api.federation import models as federation_models
from funkwhale_api.federation import routes
from funkwhale_api.music import models as music_models from funkwhale_api.music import models as music_models
from funkwhale_api.music import views as music_views from funkwhale_api.music import views as music_views
from funkwhale_api.users.oauth import permissions as oauth_permissions from funkwhale_api.users.oauth import permissions as oauth_permissions
@ -109,11 +111,13 @@ class ChannelViewSet(
@decorators.action( @decorators.action(
detail=True, detail=True,
methods=["get"], methods=["get"],
permission_classes=[],
content_negotiation_class=renderers.PodcastRSSContentNegociation, content_negotiation_class=renderers.PodcastRSSContentNegociation,
) )
def rss(self, request, *args, **kwargs): def rss(self, request, *args, **kwargs):
object = self.get_object() object = self.get_object()
if not object.attributed_to.is_local:
return response.Response({"detail": "Not found"}, status=404)
uploads = ( uploads = (
object.library.uploads.playable_by(None) object.library.uploads.playable_by(None)
.prefetch_related( .prefetch_related(
@ -142,6 +146,14 @@ class ChannelViewSet(
context["actor"] = self.request.user.actor context["actor"] = self.request.user.actor
return context return context
@transaction.atomic
def perform_destroy(self, instance):
routes.outbox.dispatch(
{"type": "Delete", "object": {"type": instance.actor.type}},
context={"actor": instance.actor},
)
instance.delete()
class SubscriptionsViewSet( class SubscriptionsViewSet(
ChannelsMixin, ChannelsMixin,

View File

@ -107,11 +107,13 @@ def test_channel_update_permission(logged_in_api_client, factories):
assert response.status_code == 403 assert response.status_code == 403
def test_channel_delete(logged_in_api_client, factories): def test_channel_delete(logged_in_api_client, factories, mocker):
actor = logged_in_api_client.user.create_actor() actor = logged_in_api_client.user.create_actor()
channel = factories["audio.Channel"](attributed_to=actor) channel = factories["audio.Channel"](attributed_to=actor)
url = reverse("api:v1:channels-detail", kwargs={"uuid": channel.uuid}) url = reverse("api:v1:channels-detail", kwargs={"uuid": channel.uuid})
dispatch = mocker.patch("funkwhale_api.federation.routes.outbox.dispatch")
response = logged_in_api_client.delete(url) response = logged_in_api_client.delete(url)
assert response.status_code == 204 assert response.status_code == 204
@ -119,6 +121,11 @@ def test_channel_delete(logged_in_api_client, factories):
with pytest.raises(channel.DoesNotExist): with pytest.raises(channel.DoesNotExist):
channel.refresh_from_db() channel.refresh_from_db()
dispatch.assert_called_once_with(
{"type": "Delete", "object": {"type": channel.actor.type}},
context={"actor": channel.actor},
)
def test_channel_delete_permission(logged_in_api_client, factories): def test_channel_delete_permission(logged_in_api_client, factories):
logged_in_api_client.user.create_actor() logged_in_api_client.user.create_actor()
@ -212,8 +219,9 @@ def test_subscriptions_all(factories, logged_in_api_client):
} }
def test_channel_rss_feed(factories, api_client): def test_channel_rss_feed(factories, api_client, preferences):
channel = factories["audio.Channel"]() preferences["common__api_authentication_required"] = False
channel = factories["audio.Channel"](local=True)
upload1 = factories["music.Upload"](library=channel.library, playable=True) upload1 = factories["music.Upload"](library=channel.library, playable=True)
upload2 = factories["music.Upload"](library=channel.library, playable=True) upload2 = factories["music.Upload"](library=channel.library, playable=True)
@ -228,3 +236,25 @@ def test_channel_rss_feed(factories, api_client):
assert response.status_code == 200 assert response.status_code == 200
assert response.data == expected assert response.data == expected
assert response["Content-Type"] == "application/rss+xml" assert response["Content-Type"] == "application/rss+xml"
def test_channel_rss_feed_remote(factories, api_client, preferences):
preferences["common__api_authentication_required"] = False
channel = factories["audio.Channel"]()
url = reverse("api:v1:channels-rss", kwargs={"uuid": channel.uuid})
response = api_client.get(url)
assert response.status_code == 404
def test_channel_rss_feed_authentication_required(factories, api_client, preferences):
preferences["common__api_authentication_required"] = True
channel = factories["audio.Channel"](local=True)
url = reverse("api:v1:channels-rss", kwargs={"uuid": channel.uuid})
response = api_client.get(url)
assert response.status_code == 401