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) Serializer)
from profiles.models import RadioProfile, SongRequest, Rating from profiles.models import RadioProfile, SongRequest, Rating
from .radio import BasicSongRetrieveSerializer from .radio import SongMinimalSerializer
User = get_user_model() User = get_user_model()
@ -44,7 +44,7 @@ class RateSongSerializer(Serializer):
class HistorySerializer(ModelSerializer): class HistorySerializer(ModelSerializer):
profile = BasicProfileSerializer() profile = BasicProfileSerializer()
song = BasicSongRetrieveSerializer() song = SongMinimalSerializer()
class Meta: class Meta:
model = SongRequest model = SongRequest
@ -52,7 +52,7 @@ class HistorySerializer(ModelSerializer):
class BasicProfileRatingsSerializer(ModelSerializer): class BasicProfileRatingsSerializer(ModelSerializer):
song = BasicSongRetrieveSerializer() song = SongMinimalSerializer()
class Meta: class Meta:
model = Rating 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, ModelSerializer, Serializer,
SerializerMethodField,
StringRelatedField) StringRelatedField)
from core.utils import iri_to_path
from radio.models import Album, Artist, Game, Song from radio.models import Album, Artist, Game, Song
class AlbumSerializer(ModelSerializer): class AlbumSerializer(ModelSerializer):
'''A base serializer for an album model.'''
class Meta: class Meta:
model = Album model = Album
fields = ('id', 'title') fields = ('id', 'title')
class ArtistSerializer(ModelSerializer): class ArtistSerializer(ModelSerializer):
'''A base serializer for an artist model.'''
class Meta: class Meta:
model = Artist model = Artist
fields = ('id', 'alias', 'first_name', 'last_name') fields = ('id', 'alias', 'first_name', 'last_name')
class ArtistFullnameSerializer(ModelSerializer): class ArtistFullnameSerializer(ModelSerializer):
'''
A base serializer for an artist model, but combining all name
attributes into one field.
'''
class Meta: class Meta:
model = Artist model = Artist
fields = ('id', 'full_name') fields = ('id', 'full_name')
class GameSerializer(ModelSerializer): class GameSerializer(ModelSerializer):
'''A base serializer for a game model.'''
class Meta: class Meta:
model = Game model = Game
fields = ('id', 'title') fields = ('id', 'title')
class BasicSongSerializer(ModelSerializer): class SongSerializer(ModelSerializer):
class Meta: '''A base serializer for a song model.'''
model = Song length = DecimalField(
fields = ('id', 'album', 'artists', 'game', 'title', 'average_rating', max_digits=10,
'is_requestable') decimal_places=2,
source='current_store.length'
)
class FullSongSerializer(ModelSerializer):
class Meta: class Meta:
model = Song model = Song
fields = ('id', 'album', 'artists', 'published_date', 'game', fields = ('id', 'album', 'artists', 'published_date', 'game',
'num_played', 'last_played', 'length', 'song_type', 'title', 'num_played', 'last_played', 'length', 'next_play',
'average_rating', 'is_requestable') 'song_type', 'title', 'average_rating', 'is_requestable')
class BasicSongRetrieveSerializer(BasicSongSerializer): class SongMinimalSerializer(ModelSerializer):
'''Minimal song information, usually appended to favorites/ratings.'''
album = AlbumSerializer() album = AlbumSerializer()
artists = ArtistFullnameSerializer(many=True) artists = ArtistFullnameSerializer(many=True)
game = GameSerializer() 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() album = AlbumSerializer()
artists = ArtistSerializer(many=True) artists = ArtistSerializer(many=True)
game = GameSerializer() game = GameSerializer()
class RadioSongSerializer(ModelSerializer): class RadioSongSerializer(ModelSerializer):
'''
A song serializer that is specific to the radio DJ and the underlying
audio manipulation application.
'''
album = StringRelatedField() album = StringRelatedField()
artists = StringRelatedField(many=True) artists = StringRelatedField(many=True)
game = StringRelatedField() game = StringRelatedField()
length = DecimalField(
max_digits=10,
decimal_places=2,
source='current_store.length'
)
path = SerializerMethodField()
class Meta: class Meta:
model = Song model = Song
fields = ('album', 'artists', 'game', 'song_type', 'title', 'length', fields = ('album', 'artists', 'game', 'song_type', 'title', 'length',
'path') '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): 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) artists = ListField(child=IntegerField(), min_length=1, max_length=10)

View file

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

View file

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