Merge pull request 'data link naar backend' (#11) from mark into master
Reviewed-on: #11
This commit was merged in pull request #11.
This commit is contained in:
@@ -1,9 +1,11 @@
|
|||||||
SPOTIFY_ENCODED_ID=<Spotify-API-Token>
|
SPOTIFY_ENCODED_ID=<Spotify-API-Token>
|
||||||
OIDC_RP_CLIENT_ID=<OIDC-Client-ID>
|
OIDC_RP_CLIENT_ID=<OIDC-Client-ID>
|
||||||
OIDC_RP_CLIENT_SECRET=<OIDC-Client-Secret>
|
OIDC_RP_CLIENT_SECRET=<OIDC-Client-Secret>
|
||||||
|
OIDC_RP_SIGN_ALGO=RS256
|
||||||
OIDC_OP_AUTHORIZATION_ENDPOINT=https://auth.yourwebsite.com/application/o/authorize/
|
OIDC_OP_AUTHORIZATION_ENDPOINT=https://auth.yourwebsite.com/application/o/authorize/
|
||||||
OIDC_OP_TOKEN_ENDPOINT=https://auth.yourwebsite.com/application/o/token/
|
OIDC_OP_TOKEN_ENDPOINT=https://auth.yourwebsite.com/application/o/token/
|
||||||
OIDC_OP_USER_ENDPOINT=https://auth.yourwebsite.com/application/o/userinfo/
|
OIDC_OP_USER_ENDPOINT=https://auth.yourwebsite.com/application/o/userinfo/
|
||||||
|
OIDC_OP_JWKS_ENDPOINT=https://auth.yourwebsite.com/application/o/name/jwks/
|
||||||
AI_ENDPOINT=http://localhost:11434/api/generate
|
AI_ENDPOINT=http://localhost:11434/api/generate
|
||||||
AI_MODEL=myModel
|
AI_MODEL=myModel
|
||||||
DATE_OPEN=<ISO-formatted date>
|
DATE_OPEN=<ISO-formatted date>
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ INSTALLED_APPS = [
|
|||||||
'django_htmx',
|
'django_htmx',
|
||||||
'rest_framework',
|
'rest_framework',
|
||||||
'corsheaders',
|
'corsheaders',
|
||||||
|
'drf_spectacular',
|
||||||
]
|
]
|
||||||
|
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
@@ -97,7 +98,14 @@ REST_FRAMEWORK = {
|
|||||||
],
|
],
|
||||||
'DEFAULT_PERMISSION_CLASSES': [
|
'DEFAULT_PERMISSION_CLASSES': [
|
||||||
'rest_framework.permissions.IsAuthenticated',
|
'rest_framework.permissions.IsAuthenticated',
|
||||||
]
|
],
|
||||||
|
'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
|
||||||
|
}
|
||||||
|
|
||||||
|
SPECTACULAR_SETTINGS = {
|
||||||
|
'TITLE': 'HDcon Muzak',
|
||||||
|
'DESCRIPTION': 'Gewoon een leuk tooltje om samen met je vrienden een muzieklijst samen te stellen.',
|
||||||
|
'VERSION': '1.0.0',
|
||||||
}
|
}
|
||||||
|
|
||||||
OIDC_RP_CLIENT_ID = os.getenv('OIDC_RP_CLIENT_ID')
|
OIDC_RP_CLIENT_ID = os.getenv('OIDC_RP_CLIENT_ID')
|
||||||
|
|||||||
@@ -1,7 +1,42 @@
|
|||||||
|
from os import extsep
|
||||||
from django.db.models.functions import Extract
|
from django.db.models.functions import Extract
|
||||||
from playlist.models import Album
|
from playlist.models import Album
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
from drf_spectacular.utils import extend_schema_serializer, OpenApiExample
|
||||||
|
|
||||||
|
@extend_schema_serializer(
|
||||||
|
examples = [
|
||||||
|
OpenApiExample(
|
||||||
|
name='Album Example',
|
||||||
|
value = {
|
||||||
|
"url": "http://muzak.hoekveen.net/api/album/7MejfRSNnrpcLZIxkeZDqR",
|
||||||
|
"name": "Leftoverture (Expanded Edition)",
|
||||||
|
"album_type": "album",
|
||||||
|
"total_tracks": 10,
|
||||||
|
"image": "http://127.0.0.1:8001/albums/Leftoverture_Expanded_Edition.png",
|
||||||
|
"image_url": "https://i.scdn.co/image/ab67616d0000b2731be40e44db112e123e5e8b51",
|
||||||
|
"artists": [
|
||||||
|
"http://127.0.0.1:8001/api/artist/2hl0xAkS2AIRAu23TVMBG1"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
),
|
||||||
|
OpenApiExample(
|
||||||
|
name = 'Multiple artist single',
|
||||||
|
value = {
|
||||||
|
"url": "http://127.0.0.1:8001/api/album/1pHD8AFu4z1CvuTPjZFOFi",
|
||||||
|
"name": "ラビリンス",
|
||||||
|
"album_type": "single",
|
||||||
|
"total_tracks": 4,
|
||||||
|
"image": None,
|
||||||
|
"image_url": "https://i.scdn.co/image/ab67616d0000b2731607d3aa3a69ca0e1ffbe26b",
|
||||||
|
"artists": [
|
||||||
|
"http://127.0.0.1:8001/api/artist/4ZX8Wr8KHHrW7radu6IwYG",
|
||||||
|
"http://127.0.0.1:8001/api/artist/4d2zOuYJHBPJTpVblHEKJb"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
class AlbumSerializer(serializers.HyperlinkedModelSerializer):
|
class AlbumSerializer(serializers.HyperlinkedModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Album
|
model = Album
|
||||||
|
|||||||
@@ -1,6 +1,27 @@
|
|||||||
from playlist.models import Artist
|
from playlist.models import Artist
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
from drf_spectacular.utils import extend_schema_serializer, OpenApiExample
|
||||||
|
|
||||||
|
@extend_schema_serializer(
|
||||||
|
examples=[
|
||||||
|
OpenApiExample(
|
||||||
|
'Daft Punk',
|
||||||
|
value = {
|
||||||
|
"id": "4tZwfgrHOc3mvqYlEYSvVi",
|
||||||
|
"name": "Daft Punk",
|
||||||
|
"url": "http://127.0.0.1:8001/api/artist/4tZwfgrHOc3mvqYlEYSvVi"
|
||||||
|
}
|
||||||
|
),
|
||||||
|
OpenApiExample(
|
||||||
|
'コリッキー',
|
||||||
|
value = {
|
||||||
|
"id": "307y5sbPNvRpXjBcZgS25q",
|
||||||
|
"name": "コリッキー",
|
||||||
|
"url": "http://127.0.0.1:8001/api/artist/307y5sbPNvRpXjBcZgS25q"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
class ArtistSerializer(serializers.HyperlinkedModelSerializer):
|
class ArtistSerializer(serializers.HyperlinkedModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Artist
|
model = Artist
|
||||||
|
|||||||
@@ -1,6 +1,51 @@
|
|||||||
from playlist.models import Track
|
from playlist.models import Track
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
from drf_spectacular.utils import extend_schema_serializer, OpenApiExample
|
||||||
|
|
||||||
|
|
||||||
|
@extend_schema_serializer(
|
||||||
|
examples = [
|
||||||
|
OpenApiExample(
|
||||||
|
'Song with banter',
|
||||||
|
value={
|
||||||
|
"url": "http://127.0.0.1:8001/api/track/0AzD1FEuvkXP1verWfaZdv",
|
||||||
|
"name": "Cbat",
|
||||||
|
"explicit": False,
|
||||||
|
"duration_ms": 171720,
|
||||||
|
"popularity": 0,
|
||||||
|
"banter": "Als je denkt dat \"Cbat\" van Hudson Mohawke de soundtrack is voor het onhandig manoeuvreren van een stelletje klunzen die elkaar constant in de weg zitten, dan heb je waarschijnlijk gelijk. Dit nummer, waarin de beats net zo chaotisch zijn als de liefdesperikelen van een tiener op een eerste date, is het perfecte liedje voor iedereen die zich ooit heeft afgevraagd hoe je een kat kunt imiteren zonder dat je daadwerkelijk een kat bent.",
|
||||||
|
"banter_done": True,
|
||||||
|
"old": False,
|
||||||
|
"from_playlist": None,
|
||||||
|
"nominated_by": "http://127.0.0.1:8001/api/user/1",
|
||||||
|
"album": "http://127.0.0.1:8001/api/album/0d99LxnQpiPLgSGDRuU9HT",
|
||||||
|
"artists": [
|
||||||
|
"http://127.0.0.1:8001/api/artist/6olWbKW2VLhFCHfOi0iEDb"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
),
|
||||||
|
OpenApiExample(
|
||||||
|
'Song from old playlist',
|
||||||
|
description='While this track is from an old playlist, old is still set to False as it has been nominated again this year.',
|
||||||
|
value={
|
||||||
|
"url": "http://127.0.0.1:8001/api/track/4QGUlo1swUpXduW23JM57S",
|
||||||
|
"name": "You Bring On The Sun",
|
||||||
|
"explicit": False,
|
||||||
|
"duration_ms": 215400,
|
||||||
|
"popularity": 43,
|
||||||
|
"banter": None,
|
||||||
|
"banter_done": False,
|
||||||
|
"old": False,
|
||||||
|
"from_playlist": "HD Con 2020 A",
|
||||||
|
"nominated_by": None,
|
||||||
|
"album": "http://127.0.0.1:8001/api/album/01QglfxMtbN2EVEyGWpPyQ",
|
||||||
|
"artists": [
|
||||||
|
"http://127.0.0.1:8001/api/artist/0gcMPgunYh4rX1UOdvZKBn"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
),
|
||||||
|
]
|
||||||
|
)
|
||||||
class TrackSerializer(serializers.HyperlinkedModelSerializer):
|
class TrackSerializer(serializers.HyperlinkedModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Track
|
model = Track
|
||||||
|
|||||||
@@ -2,10 +2,13 @@ from django.urls import path
|
|||||||
from . import views
|
from . import views
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.conf.urls.static import static
|
from django.conf.urls.static import static
|
||||||
|
from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
### API
|
### API
|
||||||
path('api/', views.api_root, name="api-root"),
|
path('api/', views.api_root, name="api-root"),
|
||||||
|
path('api/schema/', SpectacularAPIView.as_view(), name='schema'),
|
||||||
|
path('api/schema/swagger-ui/', SpectacularSwaggerView.as_view(url_name='schema'), name='swagger-ui'),
|
||||||
path('api/track/', views.TrackListView.as_view(), name="api-tracks"),
|
path('api/track/', views.TrackListView.as_view(), name="api-tracks"),
|
||||||
path('api/track/<id>', views.TrackDetailView.as_view(), name="api-track"),
|
path('api/track/<id>', views.TrackDetailView.as_view(), name="api-track"),
|
||||||
path('api/artist/<id>', views.ArtistDetailView.as_view(), name="api-artist"),
|
path('api/artist/<id>', views.ArtistDetailView.as_view(), name="api-artist"),
|
||||||
|
|||||||
@@ -2,14 +2,17 @@ from rest_framework.views import APIView
|
|||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from playlist.models import Album
|
from playlist.models import Album
|
||||||
from playlist.serializers import AlbumSerializer
|
from playlist.serializers import AlbumSerializer
|
||||||
|
from drf_spectacular.utils import extend_schema
|
||||||
|
|
||||||
class AlbumListView(APIView):
|
class AlbumListView(APIView):
|
||||||
|
@extend_schema(responses={200: AlbumSerializer(many=True)})
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
albums = Album.objects.all()
|
albums = Album.objects.all()
|
||||||
serializer = AlbumSerializer(albums, many=True, context={'request': request})
|
serializer = AlbumSerializer(albums, many=True, context={'request': request})
|
||||||
return Response(serializer.data)
|
return Response(serializer.data)
|
||||||
|
|
||||||
class AlbumDetailView(APIView):
|
class AlbumDetailView(APIView):
|
||||||
|
@extend_schema(responses={200: AlbumSerializer})
|
||||||
def get(self, request, id):
|
def get(self, request, id):
|
||||||
album = Album.objects.get(pk=id)
|
album = Album.objects.get(pk=id)
|
||||||
serializer = AlbumSerializer(album, context={'request': request})
|
serializer = AlbumSerializer(album, context={'request': request})
|
||||||
|
|||||||
@@ -3,13 +3,16 @@ from rest_framework.views import APIView
|
|||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from playlist.models import Artist
|
from playlist.models import Artist
|
||||||
from playlist.serializers import ArtistSerializer
|
from playlist.serializers import ArtistSerializer
|
||||||
|
from drf_spectacular.utils import extend_schema
|
||||||
|
|
||||||
|
@extend_schema(responses={200: ArtistSerializer(many=True)})
|
||||||
class ArtistListView(APIView):
|
class ArtistListView(APIView):
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
artists = Artist.objects.all()
|
artists = Artist.objects.all()
|
||||||
serializer = ArtistSerializer(artists, many=True, context={'request': request})
|
serializer = ArtistSerializer(artists, many=True, context={'request': request})
|
||||||
return Response(serializer.data)
|
return Response(serializer.data)
|
||||||
|
|
||||||
|
@extend_schema(responses={200: ArtistSerializer})
|
||||||
class ArtistDetailView(APIView):
|
class ArtistDetailView(APIView):
|
||||||
def get(self, request, id):
|
def get(self, request, id):
|
||||||
artist = Artist.objects.get(pk=id)
|
artist = Artist.objects.get(pk=id)
|
||||||
|
|||||||
@@ -4,13 +4,23 @@ from playlist.models import Track, Profile
|
|||||||
from playlist.serializers import TrackSerializer
|
from playlist.serializers import TrackSerializer
|
||||||
from playlist.spotify import spt
|
from playlist.spotify import spt
|
||||||
from playlist.tasks import get_banter, get_and_dither_image
|
from playlist.tasks import get_banter, get_and_dither_image
|
||||||
|
from drf_spectacular.utils import extend_schema
|
||||||
|
|
||||||
class TrackListView(APIView):
|
class TrackListView(APIView):
|
||||||
|
@extend_schema(
|
||||||
|
responses={200: TrackSerializer(many=True)},
|
||||||
|
description="Retrieve a list of all tracks."
|
||||||
|
)
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
tracks = Track.objects.all()
|
tracks = Track.objects.all()
|
||||||
serializer = TrackSerializer(tracks, many=True, context={'request': request})
|
serializer = TrackSerializer(tracks, many=True, context={'request': request})
|
||||||
return Response(serializer.data)
|
return Response(serializer.data)
|
||||||
|
|
||||||
|
@extend_schema(
|
||||||
|
request=None,
|
||||||
|
responses={201: TrackSerializer, 403: {'description': 'Forbidden'}},
|
||||||
|
description="Create a new track from a Spotify link."
|
||||||
|
)
|
||||||
def post(self, request):
|
def post(self, request):
|
||||||
(profile, _) = Profile.objects.get_or_create(user=request.user)
|
(profile, _) = Profile.objects.get_or_create(user=request.user)
|
||||||
(can_nom, reason) = profile.can_nominate
|
(can_nom, reason) = profile.can_nominate
|
||||||
@@ -20,6 +30,11 @@ class TrackListView(APIView):
|
|||||||
serializer = TrackSerializer(track, context={'request': request})
|
serializer = TrackSerializer(track, context={'request': request})
|
||||||
return Response(serializer.data)
|
return Response(serializer.data)
|
||||||
|
|
||||||
|
@extend_schema(
|
||||||
|
request=None,
|
||||||
|
responses={204: None, 403: {'description': 'Forbidden'}},
|
||||||
|
description="Delete all tracks. Only superusers are allowed."
|
||||||
|
)
|
||||||
def delete(self, request):
|
def delete(self, request):
|
||||||
if request.user.is_superuser:
|
if request.user.is_superuser:
|
||||||
Track.objects.all().delete()
|
Track.objects.all().delete()
|
||||||
@@ -28,7 +43,24 @@ class TrackListView(APIView):
|
|||||||
return Response({'error': 'Only superusers can delete all tracks'}, status=403)
|
return Response({'error': 'Only superusers can delete all tracks'}, status=403)
|
||||||
|
|
||||||
class TrackDetailView(APIView):
|
class TrackDetailView(APIView):
|
||||||
|
@extend_schema(
|
||||||
|
responses={200: TrackSerializer},
|
||||||
|
description="Retrieve a track by its ID."
|
||||||
|
)
|
||||||
def get(self, request, id):
|
def get(self, request, id):
|
||||||
track = Track.objects.get(pk=id)
|
track = Track.objects.get(pk=id)
|
||||||
serializer = TrackSerializer(track, context={'request': request})
|
serializer = TrackSerializer(track, context={'request': request})
|
||||||
return Response(serializer.data)
|
return Response(serializer.data)
|
||||||
|
|
||||||
|
@extend_schema(
|
||||||
|
request=None,
|
||||||
|
responses={204: None, 403: {'description': 'Forbidden'}},
|
||||||
|
description="Delete a single track by its ID. Only superusers are allowed."
|
||||||
|
)
|
||||||
|
def delete(self, request, id):
|
||||||
|
if request.user.is_superuser:
|
||||||
|
track = Track.objects.get(pk=id)
|
||||||
|
track.delete()
|
||||||
|
return Response(status=204)
|
||||||
|
else:
|
||||||
|
return Response({'error': 'Only superusers can delete tracks'}, status=403)
|
||||||
|
|||||||
@@ -10,3 +10,4 @@ djangorestframework
|
|||||||
markdown
|
markdown
|
||||||
PyYAML
|
PyYAML
|
||||||
Pygments
|
Pygments
|
||||||
|
drf-spectacular
|
||||||
|
|||||||
Reference in New Issue
Block a user