Updated API for new Stores and general cleanup.

This commit is contained in:
RecursiveGreen 2019-06-04 12:03:12 -04:00
parent 3afc5c7a3a
commit c305a32717
4 changed files with 91 additions and 27 deletions

View file

@ -4,7 +4,7 @@ from rest_framework.serializers import (IntegerField, ModelSerializer,
Serializer)
from profiles.models import RadioProfile, SongRequest, Rating
from .radio import BasicSongRetrieveSerializer
from .radio import SongMinimalSerializer
User = get_user_model()
@ -44,7 +44,7 @@ class RateSongSerializer(Serializer):
class HistorySerializer(ModelSerializer):
profile = BasicProfileSerializer()
song = BasicSongRetrieveSerializer()
song = SongMinimalSerializer()
class Meta:
model = SongRequest
@ -52,7 +52,7 @@ class HistorySerializer(ModelSerializer):
class BasicProfileRatingsSerializer(ModelSerializer):
song = BasicSongRetrieveSerializer()
song = SongMinimalSerializer()
class Meta:
model = Rating

View file

@ -1,71 +1,127 @@
from rest_framework.serializers import (IntegerField, ListField,
from rest_framework.serializers import (DecimalField, IntegerField, ListField,
ModelSerializer, Serializer,
SerializerMethodField,
StringRelatedField)
from core.utils import iri_to_path
from radio.models import Album, Artist, Game, Song
class AlbumSerializer(ModelSerializer):
'''A base serializer for an album model.'''
class Meta:
model = Album
fields = ('id', 'title')
class ArtistSerializer(ModelSerializer):
'''A base serializer for an artist model.'''
class Meta:
model = Artist
fields = ('id', 'alias', 'first_name', 'last_name')
class ArtistFullnameSerializer(ModelSerializer):
'''
A base serializer for an artist model, but combining all name
attributes into one field.
'''
class Meta:
model = Artist
fields = ('id', 'full_name')
class GameSerializer(ModelSerializer):
'''A base serializer for a game model.'''
class Meta:
model = Game
fields = ('id', 'title')
class BasicSongSerializer(ModelSerializer):
class Meta:
model = Song
fields = ('id', 'album', 'artists', 'game', 'title', 'average_rating',
'is_requestable')
class SongSerializer(ModelSerializer):
'''A base serializer for a song model.'''
length = DecimalField(
max_digits=10,
decimal_places=2,
source='current_store.length'
)
class FullSongSerializer(ModelSerializer):
class Meta:
model = Song
fields = ('id', 'album', 'artists', 'published_date', 'game',
'num_played', 'last_played', 'length', 'song_type', 'title',
'average_rating', 'is_requestable')
'num_played', 'last_played', 'length', 'next_play',
'song_type', 'title', 'average_rating', 'is_requestable')
class BasicSongRetrieveSerializer(BasicSongSerializer):
class SongMinimalSerializer(ModelSerializer):
'''Minimal song information, usually appended to favorites/ratings.'''
album = AlbumSerializer()
artists = ArtistFullnameSerializer(many=True)
game = GameSerializer()
class Meta:
model = Song
fields = ('id', 'album', 'artists', 'game', 'title')
class FullSongRetrieveSerializer(FullSongSerializer):
class SongListSerializer(ModelSerializer):
'''Song information used in large listings.'''
album = AlbumSerializer()
artists = ArtistFullnameSerializer(many=True)
game = GameSerializer()
length = DecimalField(
max_digits=10,
decimal_places=2,
source='current_store.length'
)
class Meta:
model = Song
fields = ('id', 'album', 'artists', 'game', 'title', 'average_rating',
'length', 'is_requestable')
class SongRetrieveSerializer(SongSerializer):
'''
An almost complete listing of a song's information, based on a single
object retrieval.
'''
album = AlbumSerializer()
artists = ArtistSerializer(many=True)
game = GameSerializer()
class RadioSongSerializer(ModelSerializer):
'''
A song serializer that is specific to the radio DJ and the underlying
audio manipulation application.
'''
album = StringRelatedField()
artists = StringRelatedField(many=True)
game = StringRelatedField()
length = DecimalField(
max_digits=10,
decimal_places=2,
source='current_store.length'
)
path = SerializerMethodField()
class Meta:
model = Song
fields = ('album', 'artists', 'game', 'song_type', 'title', 'length',
'path')
def get_path(self, obj):
'''Converts the IRI into a filesystem path.'''
iri = str(obj.current_store.iri)
if iri.startswith('file://'):
return iri_to_path(iri)
return iri
class SongArtistsListSerializer(Serializer):
'''
A serializer for adding or removing artists from a song based on
the song's id number.
'''
artists = ListField(child=IntegerField(), min_length=1, max_length=10)

View file

@ -11,7 +11,7 @@ from ..serializers.profiles import (BasicProfileSerializer,
FullProfileSerializer,
HistorySerializer,
BasicProfileRatingsSerializer)
from ..serializers.radio import BasicSongRetrieveSerializer
from ..serializers.radio import SongListSerializer
class ProfileViewSet(viewsets.ModelViewSet):
@ -52,10 +52,10 @@ class ProfileViewSet(viewsets.ModelViewSet):
page = self.paginate_queryset(favorites)
if page is not None:
serializer = BasicSongRetrieveSerializer(page, many=True)
serializer = SongListSerializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = BasicSongRetrieveSerializer(favorites, many=True)
serializer = SongListSerializer(favorites, many=True)
return Response(serializer.data)
@action(detail=True, permission_classes=[AllowAny])

View file

@ -10,9 +10,9 @@ from ..serializers.profiles import (BasicProfileSerializer,
BasicSongRatingsSerializer,
RateSongSerializer)
from ..serializers.radio import (AlbumSerializer, ArtistSerializer,
GameSerializer, FullSongSerializer,
SongArtistsListSerializer,
FullSongRetrieveSerializer)
GameSerializer, SongSerializer,
SongListSerializer, SongRetrieveSerializer,
SongArtistsListSerializer)
class AlbumViewSet(viewsets.ModelViewSet):
@ -83,9 +83,11 @@ class SongViewSet(viewsets.ModelViewSet):
(Thanks to https://stackoverflow.com/questions/22616973/)
'''
if self.action in ['list', 'retrieve']:
return FullSongRetrieveSerializer
return FullSongSerializer
if self.action == 'list':
return SongListSerializer
if self.action == 'retrieve':
return SongRetrieveSerializer
return SongSerializer
def _artists_change(self, request, remove=False):
song = self.get_object()
@ -101,20 +103,21 @@ class SongViewSet(viewsets.ModelViewSet):
message = 'Artists {} song.'.format(('added to',
'removed from')[remove])
return Response({'detail': message})
else:
return Response(serializer.errors,
status=status.HTTP_400_BAD_REQUEST)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
@action(methods=['post'], detail=True, permission_classes=[IsAdminUser])
def artists_add(self, request, pk=None):
'''Adds an artist to a song.'''
return self._artists_change(request)
@action(methods=['post'], detail=True, permission_classes=[IsAdminUser])
def artists_remove(self, request, pk=None):
'''Removes an artist from a song.'''
return self._artists_change(request, remove=True)
@action(detail=True, permission_classes=[AllowAny])
def favorites(self, request, pk=None):
'''Get a list of users who added this song to their favorites list.'''
song = self.get_object()
profiles = song.song_favorites.all().order_by('user__name')
@ -130,6 +133,7 @@ class SongViewSet(viewsets.ModelViewSet):
detail=True,
permission_classes=[IsAuthenticatedAndNotDJ])
def favorite(self, request, pk=None):
'''Add a song to the user's favorites list.'''
song = self.get_object()
profile = RadioProfile.objects.get(user=request.user)
if song not in profile.favorites.all():
@ -144,6 +148,7 @@ class SongViewSet(viewsets.ModelViewSet):
detail=True,
permission_classes=[IsAuthenticatedAndNotDJ])
def unfavorite(self, request, pk=None):
'''Remove a song from the user's favorites list.'''
song = self.get_object()
profile = RadioProfile.objects.get(user=request.user)
if song in profile.favorites.all():
@ -157,6 +162,7 @@ class SongViewSet(viewsets.ModelViewSet):
@action(detail=True, permission_classes=[AllowAny])
def ratings(self, request, pk=None):
'''Get a list of a song's ratings.'''
song = self.get_object()
ratings = song.rating_set.all().order_by('-created_date')
@ -172,6 +178,7 @@ class SongViewSet(viewsets.ModelViewSet):
detail=True,
permission_classes=[IsAuthenticatedAndNotDJ])
def rate(self, request, pk=None):
'''Add a user's rating to a song.'''
serializer = RateSongSerializer(data=request.data)
if serializer.is_valid():
song = self.get_object()
@ -195,6 +202,7 @@ class SongViewSet(viewsets.ModelViewSet):
detail=True,
permission_classes=[IsAuthenticatedAndNotDJ])
def unrate(self, request, pk=None):
'''Remove a user's rating from a song.'''
song = self.get_object()
profile = RadioProfile.objects.get(user=request.user)
rating = song.rating_set.filter(profile=profile)