Skip to content
Snippets Groups Projects
Commit 12ce41ad authored by Eliot Berriot's avatar Eliot Berriot
Browse files

Merge branch 'feature/9' into develop

parents ee62f9bf 79369196
No related branches found
No related tags found
No related merge requests found
from rest_framework import routers
from django.conf.urls import include, url
from funkwhale_api.music import views
from funkwhale_api.playlists import views as playlists_views
router = routers.SimpleRouter()
router.register(r'tags', views.TagViewSet, 'tags')
......@@ -9,6 +10,8 @@ router.register(r'artists', views.ArtistViewSet, 'artists')
router.register(r'albums', views.AlbumViewSet, 'albums')
router.register(r'import-batches', views.ImportBatchViewSet, 'import-batches')
router.register(r'submit', views.SubmitViewSet, 'submit')
router.register(r'playlists', playlists_views.PlaylistViewSet, 'playlists')
router.register(r'playlist-tracks', playlists_views.PlaylistTrackViewSet, 'playlist-tracks')
urlpatterns = router.urls
urlpatterns += [
......
......@@ -52,6 +52,7 @@ THIRD_PARTY_APPS = (
'cachalot',
'rest_auth',
'rest_auth.registration',
'mptt',
)
# Apps specific for this project go here.
......@@ -62,7 +63,7 @@ LOCAL_APPS = (
'funkwhale_api.favorites',
'funkwhale_api.radios',
'funkwhale_api.history',
# 'funkwhale_api.playlists',
'funkwhale_api.playlists',
)
# See: https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps
......
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
import versatileimagefield.fields
class Migration(migrations.Migration):
dependencies = [
('music', '0011_rename_files'),
]
operations = [
migrations.AlterField(
model_name='album',
name='cover',
field=versatileimagefield.fields.VersatileImageField(null=True, blank=True, upload_to='albums/covers/%Y/%m/%d'),
),
]
from django.contrib import admin
from . import models
@admin.register(models.Playlist)
class PlaylistAdmin(admin.ModelAdmin):
list_display = ['name', 'user', 'is_public', 'creation_date']
search_fields = ['name', ]
list_select_related = True
@admin.register(models.PlaylistTrack)
class PlaylistTrackAdmin(admin.ModelAdmin):
list_display = ['playlist', 'track', 'position', ]
search_fields = ['track__name', 'playlist__name']
list_select_related = True
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
from django.conf import settings
import django.utils.timezone
import mptt.fields
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('music', '0012_auto_20161122_1905'),
]
operations = [
migrations.CreateModel(
name='Playlist',
fields=[
('id', models.AutoField(auto_created=True, verbose_name='ID', primary_key=True, serialize=False)),
('name', models.CharField(max_length=50)),
('is_public', models.BooleanField(default=False)),
('creation_date', models.DateTimeField(default=django.utils.timezone.now)),
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL, related_name='playlists')),
],
),
migrations.CreateModel(
name='PlaylistTrack',
fields=[
('id', models.AutoField(auto_created=True, verbose_name='ID', primary_key=True, serialize=False)),
('lft', models.PositiveIntegerField(db_index=True, editable=False)),
('rght', models.PositiveIntegerField(db_index=True, editable=False)),
('tree_id', models.PositiveIntegerField(db_index=True, editable=False)),
('position', models.PositiveIntegerField(db_index=True, editable=False)),
('playlist', models.ForeignKey(to='playlists.Playlist', related_name='playlist_tracks')),
('previous', mptt.fields.TreeOneToOneField(null=True, to='playlists.PlaylistTrack', related_name='next', blank=True)),
('track', models.ForeignKey(to='music.Track', related_name='playlist_tracks')),
],
options={
'ordering': ('-playlist', 'position'),
},
),
]
from django.db import models
from django.utils import timezone
from mptt.models import MPTTModel, TreeOneToOneField
class Playlist(models.Model):
name = models.CharField(max_length=50)
......@@ -8,24 +10,24 @@ class Playlist(models.Model):
user = models.ForeignKey('users.User', related_name="playlists")
creation_date = models.DateTimeField(default=timezone.now)
def add_tracks(self, tracks):
try:
last_position = self.playlist_tracks.objects.last().position
except AttributeError:
last_position = -1
def __str__(self):
return self.name
playlist_tracks = []
for idx, track in enumerate(tracks):
plt = PlaylistTrack(position=last_position + idx +1, track=track, playlist=self)
def add_track(self, track, previous=None):
plt = PlaylistTrack(previous=previous, track=track, playlist=self)
plt.save()
playlist_tracks.append(plt)
return playlist_tracks
class PlaylistTrack(models.Model):
position = models.PositiveIntegerField(default=0)
return plt
class PlaylistTrack(MPTTModel):
track = models.ForeignKey('music.Track', related_name='playlist_tracks')
previous = TreeOneToOneField('self', blank=True, null=True, related_name='next')
playlist = models.ForeignKey(Playlist, related_name='playlist_tracks')
class MPTTMeta:
level_attr = 'position'
parent_attr = 'previous'
class Meta:
unique_together = ('playlist', 'position')
ordering = ('-playlist', 'position')
from rest_framework import serializers
from taggit.models import Tag
from funkwhale_api.music.serializers import TrackSerializerNested
from . import models
class PlaylistTrackSerializer(serializers.ModelSerializer):
track = TrackSerializerNested()
class Meta:
model = models.PlaylistTrack
fields = ('id', 'track', 'playlist', 'position')
class PlaylistTrackCreateSerializer(serializers.ModelSerializer):
class Meta:
model = models.PlaylistTrack
fields = ('id', 'track', 'playlist', 'position')
class PlaylistSerializer(serializers.ModelSerializer):
playlist_tracks = PlaylistTrackSerializer(many=True, read_only=True)
class Meta:
model = models.Playlist
fields = ('id', 'name', 'is_public', 'creation_date', 'playlist_tracks')
read_only_fields = ['id', 'playlist_tracks', 'creation_date']
......@@ -8,6 +8,8 @@ from model_mommy import mommy
from funkwhale_api.users.models import User
from funkwhale_api.playlists import models
from funkwhale_api.playlists.serializers import PlaylistSerializer
class TestPlayLists(TestCase):
......@@ -16,14 +18,48 @@ class TestPlayLists(TestCase):
self.user = User.objects.create_user(username='test', email='test@test.com', password='test')
def test_can_create_playlist(self):
tracks = mommy.make('music.Track', _quantity=5)
tracks = list(mommy.make('music.Track', _quantity=5))
playlist = models.Playlist.objects.create(user=self.user, name="test")
playlist.add_tracks(tracks)
previous = None
for i in range(len(tracks)):
previous = playlist.add_track(tracks[i], previous=previous)
playlist_tracks = list(playlist.playlist_tracks.all())
previous = None
for idx, track in enumerate(tracks):
self.assertEqual(playlist_tracks[idx].position, idx)
self.assertEqual(playlist_tracks[idx].track, track)
self.assertEqual(playlist_tracks[idx].playlist, playlist)
plt = playlist_tracks[idx]
self.assertEqual(plt.position, idx)
self.assertEqual(plt.track, track)
if previous:
self.assertEqual(playlist_tracks[idx + 1], previous)
self.assertEqual(plt.playlist, playlist)
def test_can_create_playlist_via_api(self):
self.client.login(username=self.user.username, password='test')
url = reverse('api:playlists-list')
data = {
'name': 'test',
}
response = self.client.post(url, data)
playlist = self.user.playlists.latest('id')
self.assertEqual(playlist.name, 'test')
def test_can_add_playlist_track_via_api(self):
tracks = list(mommy.make('music.Track', _quantity=5))
playlist = models.Playlist.objects.create(user=self.user, name="test")
self.client.login(username=self.user.username, password='test')
url = reverse('api:playlist-tracks-list')
data = {
'playlist': playlist.pk,
'track': tracks[0].pk
}
response = self.client.post(url, data)
plts = self.user.playlists.latest('id').playlist_tracks.all()
self.assertEqual(plts.first().track, tracks[0])
from rest_framework import generics, mixins, viewsets
from rest_framework import status
from rest_framework.response import Response
from funkwhale_api.music.models import Track
from funkwhale_api.common.permissions import ConditionalAuthentication
from . import models
from . import serializers
class PlaylistViewSet(
mixins.RetrieveModelMixin,
mixins.CreateModelMixin,
mixins.DestroyModelMixin,
mixins.ListModelMixin,
viewsets.GenericViewSet):
serializer_class = serializers.PlaylistSerializer
queryset = (models.Playlist.objects.all())
permission_classes = [ConditionalAuthentication]
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
instance = self.perform_create(serializer)
serializer = self.get_serializer(instance=instance)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
def get_queryset(self):
return self.queryset.filter(user=self.request.user)
def perform_create(self, serializer):
return serializer.save(user=self.request.user)
class PlaylistTrackViewSet(
mixins.CreateModelMixin,
mixins.DestroyModelMixin,
mixins.ListModelMixin,
viewsets.GenericViewSet):
serializer_class = serializers.PlaylistTrackSerializer
queryset = (models.PlaylistTrack.objects.all())
permission_classes = [ConditionalAuthentication]
def create(self, request, *args, **kwargs):
serializer = serializers.PlaylistTrackCreateSerializer(
data=request.data)
serializer.is_valid(raise_exception=True)
instance = self.perform_create(serializer)
serializer = self.get_serializer(instance=instance)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
def get_queryset(self):
return self.queryset.filter(playlist__user=self.request.user)
......@@ -48,6 +48,7 @@ youtube_dl>=2015.12.21
djangorestframework
djangorestframework-jwt
django-celery
django-mptt
google-api-python-client
arrow
django-taggit
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment