forked from rc/aircox
cfr #121 Co-authored-by: Christophe Siraut <d@tobald.eu.org> Co-authored-by: bkfox <thomas bkfox net> Co-authored-by: Thomas Kairos <thomas@bkfox.net> Reviewed-on: rc/aircox#131 Co-authored-by: Chris Tactic <ctactic@noreply.git.radiocampus.be> Co-committed-by: Chris Tactic <ctactic@noreply.git.radiocampus.be>
This commit is contained in:
@ -1,54 +1,34 @@
|
||||
from django_filters import rest_framework as filters
|
||||
from rest_framework import status, viewsets
|
||||
from django.contrib.auth.models import User, Group
|
||||
from django_filters import rest_framework as drf_filters
|
||||
from rest_framework import status, viewsets, parsers, permissions
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework.response import Response
|
||||
|
||||
from .models import Sound, Track
|
||||
from .serializers import SoundSerializer, admin
|
||||
from filer.models.imagemodels import Image
|
||||
|
||||
from . import models, forms, filters, serializers
|
||||
from .views import BaseAPIView
|
||||
|
||||
|
||||
__all__ = (
|
||||
"SoundFilter",
|
||||
"ImageViewSet",
|
||||
"SoundViewSet",
|
||||
"TrackFilter",
|
||||
"TrackROViewSet",
|
||||
"UserGroupViewSet",
|
||||
"UserSettingsViewSet",
|
||||
)
|
||||
|
||||
|
||||
class SoundFilter(filters.FilterSet):
|
||||
station = filters.NumberFilter(field_name="program__station__id")
|
||||
program = filters.NumberFilter(field_name="program_id")
|
||||
episode = filters.NumberFilter(field_name="episode_id")
|
||||
search = filters.CharFilter(field_name="search", method="search_filter")
|
||||
class AutocompleteMixin:
|
||||
"""Based on provided filterset and serializer, add an "autocomplete" action
|
||||
to the viewset.
|
||||
|
||||
def search_filter(self, queryset, name, value):
|
||||
return queryset.search(value)
|
||||
Url ``GET`` parameters:
|
||||
- `field` (many): if provided, only return provided field names
|
||||
- filterset's lookups.
|
||||
|
||||
|
||||
class SoundViewSet(BaseAPIView, viewsets.ModelViewSet):
|
||||
serializer_class = SoundSerializer
|
||||
queryset = Sound.objects.available().order_by("-pk")
|
||||
filter_backends = (filters.DjangoFilterBackend,)
|
||||
filterset_class = SoundFilter
|
||||
|
||||
|
||||
# --- admin
|
||||
class TrackFilter(filters.FilterSet):
|
||||
artist = filters.CharFilter(field_name="artist", lookup_expr="icontains")
|
||||
album = filters.CharFilter(field_name="album", lookup_expr="icontains")
|
||||
title = filters.CharFilter(field_name="title", lookup_expr="icontains")
|
||||
|
||||
|
||||
class TrackROViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Track viewset used for auto completion."""
|
||||
|
||||
serializer_class = admin.TrackSerializer
|
||||
permission_classes = [IsAuthenticated]
|
||||
filter_backends = (filters.DjangoFilterBackend,)
|
||||
filterset_class = TrackFilter
|
||||
queryset = Track.objects.all()
|
||||
Return a list of values if ``field`` is provided, result of `list()` otherwise.
|
||||
"""
|
||||
|
||||
@action(name="autocomplete", detail=False)
|
||||
def autocomplete(self, request):
|
||||
@ -56,18 +36,138 @@ class TrackROViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
if field:
|
||||
queryset = self.filter_queryset(self.get_queryset())
|
||||
values = queryset.values_list(field, flat=True).distinct()
|
||||
return Response(values)
|
||||
return Response(values[:10])
|
||||
return self.list(request)
|
||||
|
||||
|
||||
class ListCommitMixin:
|
||||
@action(name="commit", detail=False, methods=["POST"])
|
||||
def commit(self, request):
|
||||
"""
|
||||
Data:
|
||||
{
|
||||
"delete": [pk],
|
||||
"update": [{pk, **object}],
|
||||
"create": [object_data]
|
||||
}
|
||||
|
||||
Return:
|
||||
{
|
||||
"deleted": [pk],
|
||||
"updated": [object],
|
||||
"created": [object],
|
||||
}
|
||||
"""
|
||||
queryset = self.get_queryset()
|
||||
resp = {"deleted": [], "updated": [], "created": []}
|
||||
if ids := request.data.get("delete"):
|
||||
q = queryset.filter(id__in=ids)
|
||||
resp["deleted"] = list(q.values_list("id", flat=True))
|
||||
q.delete()
|
||||
|
||||
# TODO: bulk save and update
|
||||
if items := request.data.get("update"):
|
||||
resp["updated"] = self._commit_save_many(items)
|
||||
|
||||
if items := request.data.get("create"):
|
||||
resp["created"] = self._commit_save_many(items)
|
||||
|
||||
return Response(data=resp)
|
||||
|
||||
def _commit_save_many(self, data):
|
||||
ser = self.get_serializer(data=data, many=True)
|
||||
ser.is_valid(raise_exception=True)
|
||||
|
||||
items = ser.save()
|
||||
ser = self.get_serializer(items, many=True)
|
||||
return ser.data
|
||||
|
||||
|
||||
class ImageViewSet(viewsets.ModelViewSet):
|
||||
parsers = (parsers.MultiPartParser,)
|
||||
permissions = (permissions.IsAuthenticatedOrReadOnly,)
|
||||
serializer_class = serializers.admin.ImageSerializer
|
||||
queryset = Image.objects.all().order_by("-uploaded_at")
|
||||
filter_backends = (drf_filters.DjangoFilterBackend,)
|
||||
filterset_class = filters.ImageFilterSet
|
||||
|
||||
def create(self, request, **kwargs):
|
||||
# FIXME: to be replaced by regular DRF
|
||||
form = forms.ImageForm(request.POST, request.FILES)
|
||||
if form.is_valid():
|
||||
file = form.cleaned_data["file"]
|
||||
Image.objects.create(original_filename=file.name, file=file)
|
||||
return Response({"status": "ok"})
|
||||
return Response({"status": "error", "errors": form.errors})
|
||||
|
||||
|
||||
class SoundViewSet(BaseAPIView, viewsets.ModelViewSet):
|
||||
parsers = (parsers.MultiPartParser,)
|
||||
permissions = (permissions.IsAuthenticatedOrReadOnly,)
|
||||
serializer_class = serializers.SoundSerializer
|
||||
queryset = models.Sound.objects.order_by("-pk")
|
||||
filter_backends = (drf_filters.DjangoFilterBackend,)
|
||||
filterset_class = filters.SoundFilterSet
|
||||
|
||||
def perform_create(self, serializer):
|
||||
obj = serializer.save()
|
||||
# FIXME: hack to avoid "TYPE_REMOVED" status
|
||||
# -> file is saved to fs after object is saved to db
|
||||
obj.save()
|
||||
|
||||
def get_queryset(self):
|
||||
query = super().get_queryset()
|
||||
if not self.request.user.is_authenticated:
|
||||
return query.available()
|
||||
return query
|
||||
|
||||
|
||||
class TrackROViewSet(AutocompleteMixin, viewsets.ReadOnlyModelViewSet):
|
||||
"""Track viewset used for auto completion."""
|
||||
|
||||
serializer_class = serializers.admin.TrackSerializer
|
||||
permission_classes = (permissions.IsAuthenticated,)
|
||||
filterset_class = filters.TrackFilterSet
|
||||
queryset = models.Track.objects.all()
|
||||
|
||||
|
||||
class CommentViewSet(viewsets.ModelViewSet):
|
||||
serializer_class = serializers.CommentSerializer
|
||||
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
|
||||
queryset = models.Comment.objects.all()
|
||||
|
||||
|
||||
# --- admin
|
||||
class UserViewSet(AutocompleteMixin, viewsets.ModelViewSet):
|
||||
serializer_class = serializers.auth.UserSerializer
|
||||
permission_classes = (permissions.IsAdminUser,)
|
||||
filterset_class = filters.UserFilterSet
|
||||
queryset = User.objects.all().distinct().order_by("username")
|
||||
|
||||
|
||||
class GroupViewSet(AutocompleteMixin, viewsets.ModelViewSet):
|
||||
serializer_class = serializers.auth.GroupSerializer
|
||||
permission_classes = (permissions.IsAdminUser,)
|
||||
filterset_class = filters.GroupFilterSet
|
||||
queryset = Group.objects.all().distinct().order_by("name")
|
||||
|
||||
|
||||
class UserGroupViewSet(ListCommitMixin, viewsets.ModelViewSet):
|
||||
serializer_class = serializers.auth.UserGroupSerializer
|
||||
permission_classes = (permissions.IsAdminUser,)
|
||||
filterset_class = filters.UserGroupFilterSet
|
||||
model = User.groups.through
|
||||
queryset = model.objects.all().distinct().order_by("user__username")
|
||||
|
||||
|
||||
class UserSettingsViewSet(viewsets.ViewSet):
|
||||
"""User's settings specific to aircox.
|
||||
|
||||
Allow only to create and edit user's own settings.
|
||||
"""
|
||||
|
||||
serializer_class = admin.UserSettingsSerializer
|
||||
permission_classes = [IsAuthenticated]
|
||||
serializer_class = serializers.UserSettingsSerializer
|
||||
permission_classes = (permissions.IsAuthenticated,)
|
||||
|
||||
def get_serializer(self, instance=None, **kwargs):
|
||||
return self.serializer_class(instance=instance, context={"user": self.request.user}, **kwargs)
|
||||
|
Reference in New Issue
Block a user