mirror of
https://gitlab.science.ru.nl/technicie/MarietjeDjango.git
synced 2025-12-10 09:12:23 +01:00
Change player to OAuth protocol
This commit is contained in:
@ -129,6 +129,7 @@ OAUTH2_PROVIDER = {
|
|||||||
"write": "Authenticated write access to the website",
|
"write": "Authenticated write access to the website",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
OAUTH2_PROVIDER_APPLICATION_MODEL = "oauth2_provider.Application"
|
||||||
|
|
||||||
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
|
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
|
||||||
STATIC_URL = '/static/'
|
STATIC_URL = '/static/'
|
||||||
@ -163,3 +164,5 @@ TRUSTED_IP_RANGES = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
DEFAULT_QUEUE = 1
|
DEFAULT_QUEUE = 1
|
||||||
|
|
||||||
|
OAUTH_2_APPLICATIONS_WITH_GAIN_AND_PEAK_PERMISSION = [2]
|
||||||
|
|||||||
@ -38,6 +38,5 @@ urlpatterns = [
|
|||||||
path("beeldscherm/", partial(render, template_name="marietje/beeldscherm.html"), name="beeldscherm"),
|
path("beeldscherm/", partial(render, template_name="marietje/beeldscherm.html"), name="beeldscherm"),
|
||||||
path("songs/", include(("songs.urls", "songs"), namespace="songs")),
|
path("songs/", include(("songs.urls", "songs"), namespace="songs")),
|
||||||
path("api/", include("marietje.api.urls")),
|
path("api/", include("marietje.api.urls")),
|
||||||
path("playerapi/", include(("playerapi.urls", "playerapi"), namespace="playerapi")),
|
|
||||||
path("stats/", include(("stats.urls", "stats"), namespace="stats")),
|
path("stats/", include(("stats.urls", "stats"), namespace="stats")),
|
||||||
]
|
]
|
||||||
|
|||||||
@ -1,5 +0,0 @@
|
|||||||
from django.apps import AppConfig
|
|
||||||
|
|
||||||
|
|
||||||
class PlayerapiConfig(AppConfig):
|
|
||||||
name = "playerapi"
|
|
||||||
@ -1,15 +0,0 @@
|
|||||||
from django.contrib.auth.hashers import check_password
|
|
||||||
from django.shortcuts import get_object_or_404
|
|
||||||
from django.http import HttpResponseForbidden
|
|
||||||
|
|
||||||
from queues.models import Queue
|
|
||||||
|
|
||||||
|
|
||||||
def token_required(function):
|
|
||||||
def _dec(request):
|
|
||||||
queue = get_object_or_404(Queue, id=request.POST.get("queue"))
|
|
||||||
if not check_password(request.POST.get("player_token"), queue.player_token):
|
|
||||||
return HttpResponseForbidden()
|
|
||||||
return function(request)
|
|
||||||
|
|
||||||
return _dec
|
|
||||||
@ -1,12 +0,0 @@
|
|||||||
from django.urls import path
|
|
||||||
|
|
||||||
from . import views
|
|
||||||
|
|
||||||
app_name = "playerapi"
|
|
||||||
|
|
||||||
urlpatterns = [
|
|
||||||
path("queue/", views.queue),
|
|
||||||
path("play/", views.play),
|
|
||||||
path("next/", views.next),
|
|
||||||
path("analysed/", views.analysed),
|
|
||||||
]
|
|
||||||
@ -1,70 +0,0 @@
|
|||||||
from django.utils import timezone
|
|
||||||
|
|
||||||
from django.http import JsonResponse
|
|
||||||
from django.shortcuts import get_object_or_404
|
|
||||||
from django.views.decorators.csrf import csrf_exempt
|
|
||||||
|
|
||||||
from marietje.utils import playlist_song_to_dict
|
|
||||||
from queues.models import Queue
|
|
||||||
from songs.models import Song
|
|
||||||
|
|
||||||
from .decorators import token_required
|
|
||||||
|
|
||||||
|
|
||||||
@csrf_exempt
|
|
||||||
@token_required
|
|
||||||
def queue(request):
|
|
||||||
current_queue = get_object_or_404(Queue, id=request.POST.get("queue"))
|
|
||||||
commands = current_queue.queuecommand_set.all()
|
|
||||||
response = JsonResponse(
|
|
||||||
{
|
|
||||||
"current_song": playlist_song_to_dict(
|
|
||||||
current_queue.current_song(), include_hash=True, include_replaygain=True
|
|
||||||
),
|
|
||||||
"queue": [
|
|
||||||
playlist_song_to_dict(playlist_song, include_hash=True, include_replaygain=True)
|
|
||||||
for playlist_song in current_queue.queue()[:1]
|
|
||||||
],
|
|
||||||
"commands": [command.command for command in commands],
|
|
||||||
}
|
|
||||||
)
|
|
||||||
for command in commands:
|
|
||||||
command.delete()
|
|
||||||
|
|
||||||
return response
|
|
||||||
|
|
||||||
|
|
||||||
@csrf_exempt
|
|
||||||
@token_required
|
|
||||||
def play(request):
|
|
||||||
current_queue = get_object_or_404(Queue, id=request.POST.get("queue"))
|
|
||||||
current_queue.started_at = timezone.now()
|
|
||||||
current_queue.save()
|
|
||||||
current_song = current_queue.current_song()
|
|
||||||
current_song.played_at = current_queue.started_at
|
|
||||||
current_song.save()
|
|
||||||
|
|
||||||
return JsonResponse({})
|
|
||||||
|
|
||||||
|
|
||||||
# pylint: disable=redefined-builtin
|
|
||||||
@csrf_exempt
|
|
||||||
@token_required
|
|
||||||
def next(request):
|
|
||||||
current_queue = get_object_or_404(Queue, id=request.POST.get("queue"))
|
|
||||||
player_song = current_queue.current_song()
|
|
||||||
player_song.state = 2
|
|
||||||
player_song.save()
|
|
||||||
return JsonResponse({})
|
|
||||||
|
|
||||||
|
|
||||||
@csrf_exempt
|
|
||||||
@token_required
|
|
||||||
def analysed(request):
|
|
||||||
song = get_object_or_404(Song, id=request.POST.get("song"))
|
|
||||||
if "gain" in request.POST:
|
|
||||||
song.rg_gain = request.POST.get("gain")
|
|
||||||
if "peak" in request.POST:
|
|
||||||
song.rg_peak = request.POST.get("peak")
|
|
||||||
song.save()
|
|
||||||
return JsonResponse({})
|
|
||||||
@ -3,7 +3,7 @@ import time
|
|||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from marietje.api.v1.serializers import UserRelatedFieldSerializer
|
from marietje.api.v1.serializers import UserRelatedFieldSerializer
|
||||||
from queues.models import Queue, Playlist, PlaylistSong
|
from queues.models import Queue, Playlist, PlaylistSong, QueueCommand
|
||||||
from songs.api.v1.serializers import SongSerializer
|
from songs.api.v1.serializers import SongSerializer
|
||||||
|
|
||||||
|
|
||||||
@ -28,8 +28,8 @@ class PlaylistSerializer(serializers.ModelSerializer):
|
|||||||
|
|
||||||
|
|
||||||
class QueueSerializer(serializers.ModelSerializer):
|
class QueueSerializer(serializers.ModelSerializer):
|
||||||
current_song = serializers.SerializerMethodField()
|
current_song = serializers.SerializerMethodField(read_only=True)
|
||||||
queue = serializers.SerializerMethodField()
|
queue = serializers.SerializerMethodField(read_only=True)
|
||||||
|
|
||||||
def get_current_song(self, queue):
|
def get_current_song(self, queue):
|
||||||
return PlaylistSongSerializer(queue.current_song()).data
|
return PlaylistSongSerializer(queue.current_song()).data
|
||||||
@ -48,3 +48,18 @@ class QueueSerializer(serializers.ModelSerializer):
|
|||||||
"queue",
|
"queue",
|
||||||
"started_at",
|
"started_at",
|
||||||
]
|
]
|
||||||
|
read_only_fiels = [
|
||||||
|
"id",
|
||||||
|
"current_song",
|
||||||
|
"queue",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class QueueCommandSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = QueueCommand
|
||||||
|
fields = [
|
||||||
|
"id",
|
||||||
|
"queue",
|
||||||
|
"command",
|
||||||
|
]
|
||||||
|
|||||||
@ -11,10 +11,14 @@ from queues.api.v1.views import (
|
|||||||
QueueVolumeDownAPIView,
|
QueueVolumeDownAPIView,
|
||||||
QueueVolumeUpAPIView,
|
QueueVolumeUpAPIView,
|
||||||
QueueMuteAPIView,
|
QueueMuteAPIView,
|
||||||
|
QueueCommandListAPIView,
|
||||||
|
QueueCommandDestroyAPIView,
|
||||||
|
QueueUpdateAPIView,
|
||||||
)
|
)
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("current/", QueueAPIView.as_view(), name="queue_current"),
|
path("current/", QueueAPIView.as_view(), name="queue_current"),
|
||||||
|
path("<int:pk>/", QueueUpdateAPIView.as_view(), name="queue_update"),
|
||||||
path("current/skip/", QueueSkipAPIView.as_view(), name="queue_skip"),
|
path("current/skip/", QueueSkipAPIView.as_view(), name="queue_skip"),
|
||||||
path("current/request/", QueueRequestAPIView.as_view(), name="queue_request"),
|
path("current/request/", QueueRequestAPIView.as_view(), name="queue_request"),
|
||||||
path("current/volume-down/", QueueVolumeDownAPIView.as_view(), name="queue_volume_down"),
|
path("current/volume-down/", QueueVolumeDownAPIView.as_view(), name="queue_volume_down"),
|
||||||
@ -24,4 +28,6 @@ urlpatterns = [
|
|||||||
path("playlists/<int:pk>/", PlaylistRetrieveAPIView.as_view(), name="playlist_retrieve"),
|
path("playlists/<int:pk>/", PlaylistRetrieveAPIView.as_view(), name="playlist_retrieve"),
|
||||||
path("playlist-song/<int:id>/move-down/", PlaylistSongMoveDownAPIView.as_view(), name="playlist_song_move_down"),
|
path("playlist-song/<int:id>/move-down/", PlaylistSongMoveDownAPIView.as_view(), name="playlist_song_move_down"),
|
||||||
path("playlist-song/<int:id>/cancel/", PlaylistSongCancelAPIView.as_view(), name="playlist_song_cancel"),
|
path("playlist-song/<int:id>/cancel/", PlaylistSongCancelAPIView.as_view(), name="playlist_song_cancel"),
|
||||||
|
path("<int:pk>/commands/", QueueCommandListAPIView.as_view(), name="queue_command_list"),
|
||||||
|
path("commands/<int:pk>/", QueueCommandDestroyAPIView.as_view(), name="queue_command_destroy"),
|
||||||
]
|
]
|
||||||
|
|||||||
@ -1,4 +1,13 @@
|
|||||||
from rest_framework.generics import ListAPIView, RetrieveAPIView, get_object_or_404, CreateAPIView, DestroyAPIView
|
from oauth2_provider.views.mixins import ClientProtectedResourceMixin
|
||||||
|
from rest_framework import status, mixins
|
||||||
|
from rest_framework.generics import (
|
||||||
|
ListAPIView,
|
||||||
|
RetrieveAPIView,
|
||||||
|
get_object_or_404,
|
||||||
|
CreateAPIView,
|
||||||
|
DestroyAPIView,
|
||||||
|
UpdateAPIView,
|
||||||
|
)
|
||||||
from rest_framework.views import APIView
|
from rest_framework.views import APIView
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
|
||||||
@ -6,9 +15,14 @@ from marietje.api.openapi import CustomAutoSchema
|
|||||||
from marietje.api.permissions import IsAuthenticatedOrTokenHasScopeForMethod
|
from marietje.api.permissions import IsAuthenticatedOrTokenHasScopeForMethod
|
||||||
from django.http import Http404
|
from django.http import Http404
|
||||||
|
|
||||||
from queues.api.v1.serializers import PlaylistSerializer, QueueSerializer, PlaylistSongSerializer
|
from queues.api.v1.serializers import (
|
||||||
|
PlaylistSerializer,
|
||||||
|
QueueSerializer,
|
||||||
|
PlaylistSongSerializer,
|
||||||
|
QueueCommandSerializer,
|
||||||
|
)
|
||||||
from queues.exceptions import RequestException
|
from queues.exceptions import RequestException
|
||||||
from queues.models import Playlist, PlaylistSong, QueueCommand
|
from queues.models import Playlist, PlaylistSong, QueueCommand, Queue
|
||||||
from queues.services import get_user_or_default_queue
|
from queues.services import get_user_or_default_queue
|
||||||
from songs.counters import request_counter
|
from songs.counters import request_counter
|
||||||
from songs.models import Song
|
from songs.models import Song
|
||||||
@ -47,13 +61,58 @@ class QueueAPIView(APIView):
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
def get(self, request, **kwargs):
|
def get_object(self):
|
||||||
queue = get_user_or_default_queue(request)
|
queue = get_user_or_default_queue(self.request)
|
||||||
if queue is None:
|
if queue is None:
|
||||||
raise Http404()
|
raise Http404()
|
||||||
|
return queue
|
||||||
|
|
||||||
|
def get(self, request, **kwargs):
|
||||||
|
queue = self.get_object()
|
||||||
return Response(status=200, data=self.serializer_class(queue).data)
|
return Response(status=200, data=self.serializer_class(queue).data)
|
||||||
|
|
||||||
|
|
||||||
|
class QueueUpdateAPIView(ClientProtectedResourceMixin, UpdateAPIView):
|
||||||
|
serializer_class = QueueSerializer
|
||||||
|
queryset = Queue.objects.all()
|
||||||
|
permission_classes = [IsAuthenticatedOrTokenHasScopeForMethod]
|
||||||
|
required_scopes_for_method = {"PUT": ["write"], "PATCH": ["write"]}
|
||||||
|
schema = CustomAutoSchema(
|
||||||
|
response_schema={
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {"type": "int", "example": 1},
|
||||||
|
"name": {"type": "string", "example": "string"},
|
||||||
|
"playlist": {"type": "int", "example": 1},
|
||||||
|
"random_playlist": {"type": "int", "example": 1},
|
||||||
|
"current_song": {"$ref": "#/components/schemas/PlaylistSong"},
|
||||||
|
"queue": {"type": "array", "items": {"$ref": "#/components/schemas/PlaylistSong"}},
|
||||||
|
"started_at": {"type": "string", "format": "date-time", "nullable": True},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
def put(self, request, **kwargs):
|
||||||
|
queue = self.get_object()
|
||||||
|
if queue.oauth_client is None or queue.oauth_client != request.auth.application:
|
||||||
|
return Response(
|
||||||
|
{"detail": "Unauthorized"},
|
||||||
|
status=status.HTTP_401_UNAUTHORIZED,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return super(QueueUpdateAPIView, self).put(request, **kwargs)
|
||||||
|
|
||||||
|
def patch(self, request, **kwargs):
|
||||||
|
queue = self.get_object()
|
||||||
|
if queue.oauth_client is None or queue.oauth_client != request.auth.application:
|
||||||
|
return Response(
|
||||||
|
{"detail": "Unauthorized"},
|
||||||
|
status=status.HTTP_401_UNAUTHORIZED,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return super(QueueUpdateAPIView, self).patch(request, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class QueueSkipAPIView(APIView):
|
class QueueSkipAPIView(APIView):
|
||||||
serializer_class = QueueSerializer
|
serializer_class = QueueSerializer
|
||||||
permission_classes = [IsAuthenticatedOrTokenHasScopeForMethod]
|
permission_classes = [IsAuthenticatedOrTokenHasScopeForMethod]
|
||||||
@ -80,12 +139,14 @@ class QueueSkipAPIView(APIView):
|
|||||||
if queue is None:
|
if queue is None:
|
||||||
return Response(status=404)
|
return Response(status=404)
|
||||||
|
|
||||||
playlist_song = request.user.queue.current_song()
|
playlist_song = queue.current_song()
|
||||||
if (
|
if request.user is not None:
|
||||||
request.user is not None
|
if playlist_song.user != request.user and not request.user.has_perm("queues.can_skip"):
|
||||||
and playlist_song.user != request.user
|
return Response(status=403)
|
||||||
and not request.user.has_perm("queues.can_skip")
|
elif request.auth is not None:
|
||||||
):
|
if queue.oauth_client is None or request.auth.application != queue.oauth_client:
|
||||||
|
return Response(status=403)
|
||||||
|
else:
|
||||||
return Response(status=403)
|
return Response(status=403)
|
||||||
|
|
||||||
playlist_song.state = 2
|
playlist_song.state = 2
|
||||||
@ -260,3 +321,41 @@ class QueueMuteAPIView(APIView):
|
|||||||
return Response(status=403)
|
return Response(status=403)
|
||||||
QueueCommand.objects.create(queue=queue, command="mute")
|
QueueCommand.objects.create(queue=queue, command="mute")
|
||||||
return Response(status=200, data=self.serializer_class(queue).data)
|
return Response(status=200, data=self.serializer_class(queue).data)
|
||||||
|
|
||||||
|
|
||||||
|
class QueueCommandListAPIView(ClientProtectedResourceMixin, ListAPIView):
|
||||||
|
serializer_class = QueueCommandSerializer
|
||||||
|
queryset = QueueCommand.objects.all()
|
||||||
|
permission_classes = [IsAuthenticatedOrTokenHasScopeForMethod]
|
||||||
|
required_scopes_for_method = {"GET": ["read"]}
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
queue = get_object_or_404(Queue, pk=self.kwargs.get("pk"))
|
||||||
|
self.queryset.filter(queue=queue)
|
||||||
|
|
||||||
|
def get(self, request, **kwargs):
|
||||||
|
queue = get_object_or_404(Queue, pk=kwargs.get("pk"))
|
||||||
|
if queue.oauth_client is None or queue.oauth_client != request.auth.application:
|
||||||
|
return Response(
|
||||||
|
{"detail": "Unauthorized"},
|
||||||
|
status=status.HTTP_401_UNAUTHORIZED,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return super(QueueCommandListAPIView, self).get(request, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class QueueCommandDestroyAPIView(ClientProtectedResourceMixin, DestroyAPIView):
|
||||||
|
serializer_class = QueueCommandSerializer
|
||||||
|
queryset = QueueCommand.objects.all()
|
||||||
|
permission_classes = [IsAuthenticatedOrTokenHasScopeForMethod]
|
||||||
|
required_scopes_for_method = {"DELETE": ["write"]}
|
||||||
|
|
||||||
|
def delete(self, request, **kwargs):
|
||||||
|
queue_command = self.get_object()
|
||||||
|
if queue_command.queue.oauth_client is None or queue_command.queue.oauth_client != request.auth.application:
|
||||||
|
return Response(
|
||||||
|
{"detail": "Unauthorized"},
|
||||||
|
status=status.HTTP_401_UNAUTHORIZED,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return super(QueueCommandDestroyAPIView, self).delete(request, **kwargs)
|
||||||
|
|||||||
27
marietje/queues/migrations/0012_queue_oauth_client.py
Normal file
27
marietje/queues/migrations/0012_queue_oauth_client.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# Generated by Django 4.2.6 on 2023-11-05 14:33
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
migrations.swappable_dependency(settings.OAUTH2_PROVIDER_APPLICATION_MODEL),
|
||||||
|
("queues", "0011_alter_playlistsong_playlist"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="queue",
|
||||||
|
name="oauth_client",
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
help_text="The OAuth2 client that may read and write commands for this Queue.",
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.SET_NULL,
|
||||||
|
related_name="queues",
|
||||||
|
to=settings.OAUTH2_PROVIDER_APPLICATION_MODEL,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
||||||
@ -2,6 +2,7 @@ from django.db import models
|
|||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
from oauth2_provider.models import Application
|
||||||
|
|
||||||
from queues.exceptions import RequestException
|
from queues.exceptions import RequestException
|
||||||
from songs.models import Song
|
from songs.models import Song
|
||||||
@ -81,6 +82,14 @@ class Queue(models.Model):
|
|||||||
)
|
)
|
||||||
started_at = models.DateTimeField(blank=True, null=True)
|
started_at = models.DateTimeField(blank=True, null=True)
|
||||||
player_token = models.TextField(blank=True, null=True)
|
player_token = models.TextField(blank=True, null=True)
|
||||||
|
oauth_client = models.ForeignKey(
|
||||||
|
Application,
|
||||||
|
on_delete=models.SET_NULL,
|
||||||
|
help_text="The OAuth2 client that may read and write commands for this Queue.",
|
||||||
|
related_name="queues",
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
)
|
||||||
|
|
||||||
def get_songs(self):
|
def get_songs(self):
|
||||||
self.fill_random_queue()
|
self.fill_random_queue()
|
||||||
|
|||||||
@ -5,11 +5,12 @@ from songs.models import Song, ReportNote
|
|||||||
|
|
||||||
|
|
||||||
class SongSerializer(serializers.ModelSerializer):
|
class SongSerializer(serializers.ModelSerializer):
|
||||||
user = UserRelatedFieldSerializer()
|
user = UserRelatedFieldSerializer(read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Song
|
model = Song
|
||||||
fields = ["id", "artist", "title", "duration", "hash", "user", "rg_gain", "rg_peak"]
|
fields = ["id", "artist", "title", "duration", "hash", "user", "rg_gain", "rg_peak"]
|
||||||
|
read_only_fields = ["id", "duration", "hash", "user"]
|
||||||
|
|
||||||
|
|
||||||
class ReportNoteSerializer(serializers.ModelSerializer):
|
class ReportNoteSerializer(serializers.ModelSerializer):
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
from django.urls import path
|
from django.urls import path
|
||||||
|
|
||||||
from .views import SongsListAPIView, SongRetrieveAPIView, SongUploadAPIView, ReportNoteCreateAPIView
|
from .views import SongsListAPIView, SongRetrieveUpdateAPIView, SongUploadAPIView, ReportNoteCreateAPIView
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("", SongsListAPIView.as_view(), name="song_list"),
|
path("", SongsListAPIView.as_view(), name="song_list"),
|
||||||
path("<int:pk>/", SongRetrieveAPIView.as_view(), name="song_retrieve"),
|
path("<int:pk>/", SongRetrieveUpdateAPIView.as_view(), name="song_retrieve_update"),
|
||||||
path("report-notes/", ReportNoteCreateAPIView.as_view(), name="report_note_create"),
|
path("report-notes/", ReportNoteCreateAPIView.as_view(), name="report_note_create"),
|
||||||
path("upload/", SongUploadAPIView.as_view(), name="song_upload"),
|
path("upload/", SongUploadAPIView.as_view(), name="song_upload"),
|
||||||
]
|
]
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
|
from django.conf import settings
|
||||||
from django_filters.rest_framework import DjangoFilterBackend
|
from django_filters.rest_framework import DjangoFilterBackend
|
||||||
from rest_framework.generics import ListAPIView, RetrieveAPIView, CreateAPIView
|
from rest_framework.generics import ListAPIView, RetrieveUpdateAPIView, CreateAPIView
|
||||||
from rest_framework import filters
|
from rest_framework import filters, status
|
||||||
from rest_framework.views import APIView
|
from rest_framework.views import APIView
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
|
||||||
@ -27,11 +28,35 @@ class SongsListAPIView(ListAPIView):
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class SongRetrieveAPIView(RetrieveAPIView):
|
class SongRetrieveUpdateAPIView(RetrieveUpdateAPIView):
|
||||||
serializer_class = SongSerializer
|
serializer_class = SongSerializer
|
||||||
queryset = Song.objects.all()
|
queryset = Song.objects.all()
|
||||||
permission_classes = [IsAuthenticatedOrTokenHasScopeForMethod]
|
permission_classes = [IsAuthenticatedOrTokenHasScopeForMethod]
|
||||||
required_scopes_for_method = {"GET": ["read"]}
|
required_scopes_for_method = {"GET": ["read"], "PUT": ["write"], "PATCH": ["write"]}
|
||||||
|
|
||||||
|
def put(self, request, **kwargs):
|
||||||
|
if (
|
||||||
|
request.auth is None
|
||||||
|
or request.auth.application.id not in settings.OAUTH_2_APPLICATIONS_WITH_GAIN_AND_PEAK_PERMISSION
|
||||||
|
):
|
||||||
|
return Response(
|
||||||
|
{"detail": "Unauthorized"},
|
||||||
|
status=status.HTTP_401_UNAUTHORIZED,
|
||||||
|
)
|
||||||
|
|
||||||
|
return super(SongRetrieveUpdateAPIView, self).put(request, **kwargs)
|
||||||
|
|
||||||
|
def patch(self, request, **kwargs):
|
||||||
|
if (
|
||||||
|
request.auth is None
|
||||||
|
or request.auth.application.id not in settings.OAUTH_2_APPLICATIONS_WITH_GAIN_AND_PEAK_PERMISSION
|
||||||
|
):
|
||||||
|
return Response(
|
||||||
|
{"detail": "Unauthorized"},
|
||||||
|
status=status.HTTP_401_UNAUTHORIZED,
|
||||||
|
)
|
||||||
|
|
||||||
|
return super(SongRetrieveUpdateAPIView, self).patch(request, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class ReportNoteCreateAPIView(CreateAPIView):
|
class ReportNoteCreateAPIView(CreateAPIView):
|
||||||
|
|||||||
Reference in New Issue
Block a user