Skip to content

Commit 7eb661d

Browse files
committed
Fix: RBAC private media visibility in playlists
Private media assigned to RBAC categories was visible in category views and detail pages for authorized group members, but not in playlists. This inconsistency occurred because the playlist view only checked media state (public/unlisted) instead of applying the same permission logic used elsewhere. Changes: - Add MediaPermission import to playlists.py - Create _get_accessible_media_filter() helper method that builds Q object for media visibility based on: * listable=True (public media) * Direct MediaPermission for the user * RBAC category membership (when USE_RBAC=True) - Update PlaylistDetail.get() to use permission filter instead of simple state check for non-owners The implementation now matches the permission logic in _get_media_queryset() from files/views/media.py, ensuring consistent behavior across the application. Fixes #1370
1 parent 8725713 commit 7eb661d

1 file changed

Lines changed: 30 additions & 3 deletions

File tree

files/views/playlists.py

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
from cms.permissions import IsAuthorizedToAdd, IsUserOrEditor
1818

19-
from ..models import Media, Playlist, PlaylistMedia
19+
from ..models import Media, MediaPermission, Playlist, PlaylistMedia
2020
from ..serializers import MediaSerializer, PlaylistDetailSerializer, PlaylistSerializer
2121

2222

@@ -82,6 +82,31 @@ def get_playlist(self, friendly_token):
8282
status=status.HTTP_400_BAD_REQUEST,
8383
)
8484

85+
def _get_accessible_media_filter(self, request):
86+
"""
87+
Build a Q object that filters media based on user permissions.
88+
Returns media that is:
89+
- listable (public)
90+
- has direct MediaPermission for the user
91+
- accessible via RBAC category membership (if USE_RBAC is enabled)
92+
"""
93+
conditions = Q(media__listable=True)
94+
95+
if not request.user.is_authenticated:
96+
return conditions
97+
98+
# Check for direct MediaPermission
99+
if MediaPermission.objects.filter(user=request.user).exists():
100+
conditions |= Q(media__permissions__user=request.user)
101+
102+
# Check for RBAC access
103+
if getattr(settings, 'USE_RBAC', False):
104+
rbac_categories = request.user.get_rbac_categories_as_member()
105+
if rbac_categories.exists():
106+
conditions |= Q(media__category__in=rbac_categories)
107+
108+
return conditions
109+
85110
@swagger_auto_schema(
86111
manual_parameters=[],
87112
tags=['Playlists'],
@@ -95,11 +120,13 @@ def get(self, request, friendly_token, format=None):
95120

96121
serializer = PlaylistDetailSerializer(playlist, context={"request": request})
97122

98-
# If user is the author, show all media; otherwise, show only public and unlisted media
123+
# If user is the author, show all media; otherwise, filter based on permissions (RBAC, direct permissions, or listable)
99124
if request.user.is_authenticated and request.user == playlist.user:
100125
playlist_media = PlaylistMedia.objects.filter(playlist=playlist).prefetch_related("media__user").select_related("media")
101126
else:
102-
playlist_media = PlaylistMedia.objects.filter(playlist=playlist).filter(Q(media__state="public") | Q(media__state="unlisted")).prefetch_related("media__user").select_related("media")
127+
# Apply permission filter to show media accessible via RBAC, direct permissions, or public visibility
128+
accessible_filter = self._get_accessible_media_filter(request)
129+
playlist_media = PlaylistMedia.objects.filter(playlist=playlist).filter(accessible_filter).prefetch_related("media__user").select_related("media").distinct()
103130

104131
playlist_media = [c.media for c in playlist_media]
105132

0 commit comments

Comments
 (0)