diff --git a/api/config/settings/common.py b/api/config/settings/common.py
index 13624511c..3000feddb 100644
--- a/api/config/settings/common.py
+++ b/api/config/settings/common.py
@@ -536,11 +536,11 @@ REST_FRAMEWORK = {
),
"DEFAULT_AUTHENTICATION_CLASSES": (
"oauth2_provider.contrib.rest_framework.OAuth2Authentication",
- "rest_framework.authentication.SessionAuthentication",
"funkwhale_api.common.authentication.JSONWebTokenAuthenticationQS",
"funkwhale_api.common.authentication.BearerTokenHeaderAuth",
"funkwhale_api.common.authentication.JSONWebTokenAuthentication",
"rest_framework.authentication.BasicAuthentication",
+ "rest_framework.authentication.SessionAuthentication",
),
"DEFAULT_PERMISSION_CLASSES": (
"funkwhale_api.users.oauth.permissions.ScopePermission",
diff --git a/api/funkwhale_api/common/permissions.py b/api/funkwhale_api/common/permissions.py
index 4ab405eb4..237fc4ae4 100644
--- a/api/funkwhale_api/common/permissions.py
+++ b/api/funkwhale_api/common/permissions.py
@@ -47,6 +47,6 @@ class OwnerPermission(BasePermission):
owner_field = getattr(view, "owner_field", "user")
owner = operator.attrgetter(owner_field)(obj)
- if owner != request.user:
+ if not owner or not request.user.is_authenticated or owner != request.user:
raise Http404
return True
diff --git a/api/funkwhale_api/radios/radios.py b/api/funkwhale_api/radios/radios.py
index f19c6b884..a0dc36b62 100644
--- a/api/funkwhale_api/radios/radios.py
+++ b/api/funkwhale_api/radios/radios.py
@@ -47,6 +47,8 @@ class SessionRadio(SimpleRadio):
qs = Track.objects.all()
if not self.session:
return qs
+ if not self.session.user:
+ return qs
query = moderation_filters.get_filtered_content_query(
config=moderation_filters.USER_FILTER_CONFIG["TRACK"],
user=self.session.user,
@@ -62,7 +64,9 @@ class SessionRadio(SimpleRadio):
if self.session:
queryset = self.filter_from_session(queryset)
if kwargs.pop("filter_playable", True):
- queryset = queryset.playable_by(self.session.user.actor)
+ queryset = queryset.playable_by(
+ self.session.user.actor if self.session.user else None
+ )
queryset = self.filter_queryset(queryset)
return queryset
@@ -129,7 +133,7 @@ class CustomRadio(SessionRadio):
try:
user = data["user"]
except KeyError:
- user = context["user"]
+ user = context.get("user")
try:
assert data["custom_radio"].user == user or data["custom_radio"].is_public
except KeyError:
diff --git a/api/funkwhale_api/radios/serializers.py b/api/funkwhale_api/radios/serializers.py
index 9bffbf5b9..397452ecc 100644
--- a/api/funkwhale_api/radios/serializers.py
+++ b/api/funkwhale_api/radios/serializers.py
@@ -70,7 +70,7 @@ class RadioSessionSerializer(serializers.ModelSerializer):
return data
def create(self, validated_data):
- validated_data["user"] = self.context["user"]
+ validated_data["user"] = self.context.get("user")
if validated_data.get("related_object_id"):
radio = registry[validated_data["radio_type"]]()
validated_data["related_object"] = radio.get_related_object(
diff --git a/api/funkwhale_api/radios/views.py b/api/funkwhale_api/radios/views.py
index fa0a6fe4a..0a5f1cd6c 100644
--- a/api/funkwhale_api/radios/views.py
+++ b/api/funkwhale_api/radios/views.py
@@ -1,5 +1,5 @@
from django.db.models import Q
-from rest_framework import mixins, permissions, status, viewsets
+from rest_framework import mixins, status, viewsets
from rest_framework.decorators import action
from rest_framework.response import Response
@@ -28,6 +28,7 @@ class RadioViewSet(
required_scope = "radios"
owner_field = "user"
owner_checks = ["write"]
+ anonymous_policy = "setting"
def get_queryset(self):
queryset = models.Radio.objects.all()
@@ -82,11 +83,30 @@ class RadioSessionViewSet(
serializer_class = serializers.RadioSessionSerializer
queryset = models.RadioSession.objects.all()
- permission_classes = [permissions.IsAuthenticated]
+ permission_classes = []
def get_queryset(self):
queryset = super().get_queryset()
- return queryset.filter(user=self.request.user)
+ if self.request.user.is_authenticated:
+ return queryset.filter(
+ Q(user=self.request.user)
+ | Q(session_key=self.request.session.session_key)
+ )
+
+ return queryset.filter(session_key=self.request.session.session_key).exclude(
+ session_key=None
+ )
+
+ def perform_create(self, serializer):
+ if (
+ not self.request.user.is_authenticated
+ and not self.request.session.session_key
+ ):
+ self.request.session.create()
+ return serializer.save(
+ user=self.request.user if self.request.user.is_authenticated else None,
+ session_key=self.request.session.session_key,
+ )
def get_serializer_context(self):
context = super().get_serializer_context()
@@ -97,14 +117,19 @@ class RadioSessionViewSet(
class RadioSessionTrackViewSet(mixins.CreateModelMixin, viewsets.GenericViewSet):
serializer_class = serializers.RadioSessionTrackSerializer
queryset = models.RadioSessionTrack.objects.all()
- permission_classes = [permissions.IsAuthenticated]
+ permission_classes = []
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
session = serializer.validated_data["session"]
+ if not request.user.is_authenticated and not request.session.session_key:
+ self.request.session.create()
try:
- assert request.user == session.user
+ assert (request.user == session.user) or (
+ request.session.session_key == session.session_key
+ and session.session_key
+ )
except AssertionError:
return Response(status=status.HTTP_403_FORBIDDEN)
session.radio.pick()
diff --git a/changes/changelog.d/563.bugfix b/changes/changelog.d/563.bugfix
new file mode 100644
index 000000000..14f49b75e
--- /dev/null
+++ b/changes/changelog.d/563.bugfix
@@ -0,0 +1 @@
+Fixed unplayable radios for anonymous users (#563)
diff --git a/front/src/components/library/Radios.vue b/front/src/components/library/Radios.vue
index 68eb11f0b..9b2f7bf82 100644
--- a/front/src/components/library/Radios.vue
+++ b/front/src/components/library/Radios.vue
@@ -10,9 +10,9 @@