From 99a91c1e74604c278e87b79b0e66acb5fe3da0c2 Mon Sep 17 00:00:00 2001 From: Eliot Berriot Date: Wed, 7 Mar 2018 22:36:37 +0100 Subject: [PATCH 01/69] Fix #115: broken import request admin --- api/funkwhale_api/requests/admin.py | 3 +-- changes/changelog.d/115.bugfix | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 changes/changelog.d/115.bugfix diff --git a/api/funkwhale_api/requests/admin.py b/api/funkwhale_api/requests/admin.py index 71933eaa9..8ca008a03 100644 --- a/api/funkwhale_api/requests/admin.py +++ b/api/funkwhale_api/requests/admin.py @@ -7,8 +7,7 @@ from . import models class ImportRequestAdmin(admin.ModelAdmin): list_display = ['artist_name', 'user', 'status', 'creation_date'] list_select_related = [ - 'user', - 'track' + 'user' ] list_filter = [ 'status', diff --git a/changes/changelog.d/115.bugfix b/changes/changelog.d/115.bugfix new file mode 100644 index 000000000..96da61f09 --- /dev/null +++ b/changes/changelog.d/115.bugfix @@ -0,0 +1 @@ +Fixed broken import request admin (#115) From 7e593ad05bf6aa15d93ecd572b2b24a86b1c0d42 Mon Sep 17 00:00:00 2001 From: Eliot Berriot Date: Wed, 7 Mar 2018 23:02:33 +0100 Subject: [PATCH 02/69] Added year filter --- front/src/filters.js | 6 ++++++ front/test/unit/specs/filters/filters.spec.js | 9 ++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/front/src/filters.js b/front/src/filters.js index 22d93149b..afc393d40 100644 --- a/front/src/filters.js +++ b/front/src/filters.js @@ -35,6 +35,12 @@ export function momentFormat (date, format) { Vue.filter('moment', momentFormat) +export function year (date) { + return moment(date).year() +} + +Vue.filter('year', year) + export function capitalize (str) { return str.charAt(0).toUpperCase() + str.slice(1) } diff --git a/front/test/unit/specs/filters/filters.spec.js b/front/test/unit/specs/filters/filters.spec.js index c2b43da44..f4789ca48 100644 --- a/front/test/unit/specs/filters/filters.spec.js +++ b/front/test/unit/specs/filters/filters.spec.js @@ -1,4 +1,4 @@ -import {truncate, markdown, ago, capitalize} from '@/filters' +import {truncate, markdown, ago, capitalize, year} from '@/filters' describe('filters', () => { describe('truncate', () => { @@ -32,6 +32,13 @@ describe('filters', () => { expect(output).to.equal('a few seconds ago') }) }) + describe('year', () => { + it('works', () => { + const input = '2017-07-13' + let output = year(input) + expect(output).to.equal(2017) + }) + }) describe('capitalize', () => { it('works', () => { const input = 'hello world' From 1822fdf4499fb01b96eed5f2af6e5644d4e76e72 Mon Sep 17 00:00:00 2001 From: Eliot Berriot Date: Wed, 7 Mar 2018 23:03:46 +0100 Subject: [PATCH 03/69] Fix #116: On artist page, albums are not sorted by release date, if any --- changes/changelog.d/116.feature | 1 + front/src/components/audio/album/Card.vue | 9 +++++---- front/src/components/library/Artist.vue | 7 ++++++- 3 files changed, 12 insertions(+), 5 deletions(-) create mode 100644 changes/changelog.d/116.feature diff --git a/changes/changelog.d/116.feature b/changes/changelog.d/116.feature new file mode 100644 index 000000000..e17343401 --- /dev/null +++ b/changes/changelog.d/116.feature @@ -0,0 +1 @@ +On artist page, albums are not sorted by release date, if any (#116) diff --git a/front/src/components/audio/album/Card.vue b/front/src/components/audio/album/Card.vue index ea42f06a8..bb37b2b2f 100644 --- a/front/src/components/audio/album/Card.vue +++ b/front/src/components/audio/album/Card.vue @@ -6,12 +6,13 @@
- {{ album.title }} + {{ album.title }}
- By - {{ album.artist.name }} - + + By + {{ album.artist.name }} + – {{ album.release_date | year }}
diff --git a/front/src/components/library/Artist.vue b/front/src/components/library/Artist.vue index 7724428ca..9a546aa0e 100644 --- a/front/src/components/library/Artist.vue +++ b/front/src/components/library/Artist.vue @@ -31,7 +31,7 @@

Albums by this artist

-
+
@@ -41,6 +41,7 @@ + + + diff --git a/front/src/components/playlists/PlaylistModal.vue b/front/src/components/playlists/PlaylistModal.vue new file mode 100644 index 000000000..2e1627001 --- /dev/null +++ b/front/src/components/playlists/PlaylistModal.vue @@ -0,0 +1,91 @@ + + + + + + diff --git a/front/src/components/playlists/TrackPlaylistIcon.vue b/front/src/components/playlists/TrackPlaylistIcon.vue new file mode 100644 index 000000000..2684f7cb6 --- /dev/null +++ b/front/src/components/playlists/TrackPlaylistIcon.vue @@ -0,0 +1,40 @@ + + + + + + From 08b28a7d9864f6fec0f01df4c33b772f42cfb9aa Mon Sep 17 00:00:00 2001 From: Eliot Berriot Date: Mon, 19 Mar 2018 19:07:45 +0100 Subject: [PATCH 44/69] Added playlist tracks count and modification date in API --- .../migrations/0004_auto_20180319_1642.py | 23 +++++++++++++++++++ api/funkwhale_api/playlists/models.py | 5 ++++ api/funkwhale_api/playlists/serializers.py | 21 +++++++++++++++-- api/funkwhale_api/playlists/views.py | 9 +++++++- api/tests/playlists/test_models.py | 2 ++ api/tests/playlists/test_views.py | 10 ++++++++ 6 files changed, 67 insertions(+), 3 deletions(-) create mode 100644 api/funkwhale_api/playlists/migrations/0004_auto_20180319_1642.py diff --git a/api/funkwhale_api/playlists/migrations/0004_auto_20180319_1642.py b/api/funkwhale_api/playlists/migrations/0004_auto_20180319_1642.py new file mode 100644 index 000000000..f4a525291 --- /dev/null +++ b/api/funkwhale_api/playlists/migrations/0004_auto_20180319_1642.py @@ -0,0 +1,23 @@ +# Generated by Django 2.0.3 on 2018-03-19 16:42 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('playlists', '0003_auto_20180319_1214'), + ] + + operations = [ + migrations.AddField( + model_name='playlist', + name='modification_date', + field=models.DateTimeField(auto_now=True), + ), + migrations.AlterField( + model_name='playlisttrack', + name='index', + field=models.PositiveIntegerField(blank=True, null=True), + ), + ] diff --git a/api/funkwhale_api/playlists/models.py b/api/funkwhale_api/playlists/models.py index d8c90aef9..f26dbeff4 100644 --- a/api/funkwhale_api/playlists/models.py +++ b/api/funkwhale_api/playlists/models.py @@ -11,6 +11,8 @@ class Playlist(models.Model): user = models.ForeignKey( 'users.User', related_name="playlists", on_delete=models.CASCADE) creation_date = models.DateTimeField(default=timezone.now) + modification_date = models.DateTimeField( + auto_now=True) privacy_level = fields.get_privacy_field() def __str__(self): @@ -65,10 +67,13 @@ class Playlist(models.Model): plt.index = index plt.save(update_fields=['index']) + self.save(update_fields=['modification_date']) return index + @transaction.atomic def remove(self, index): existing = self.playlist_tracks.select_for_update() + self.save(update_fields=['modification_date']) to_update = existing.filter(index__gt=index) return to_update.update(index=models.F('index') - 1) diff --git a/api/funkwhale_api/playlists/serializers.py b/api/funkwhale_api/playlists/serializers.py index 43e2414d4..0680dc8d0 100644 --- a/api/funkwhale_api/playlists/serializers.py +++ b/api/funkwhale_api/playlists/serializers.py @@ -62,8 +62,25 @@ class PlaylistTrackWriteSerializer(serializers.ModelSerializer): class PlaylistSerializer(serializers.ModelSerializer): + tracks_count = serializers.SerializerMethodField() class Meta: model = models.Playlist - fields = ('id', 'name', 'privacy_level', 'creation_date') - read_only_fields = ['id', 'creation_date'] + fields = ( + 'id', + 'name', + 'tracks_count', + 'privacy_level', + 'creation_date', + 'modification_date') + read_only_fields = [ + 'id', + 'modification_date', + 'creation_date',] + + def get_tracks_count(self, obj): + try: + return obj.tracks_count + except AttributeError: + # no annotation? + return obj.playlist_tracks.count() diff --git a/api/funkwhale_api/playlists/views.py b/api/funkwhale_api/playlists/views.py index 02e53cb16..dc3475fab 100644 --- a/api/funkwhale_api/playlists/views.py +++ b/api/funkwhale_api/playlists/views.py @@ -1,3 +1,5 @@ +from django.db.models import Count + from rest_framework import generics, mixins, viewsets from rest_framework import status from rest_framework.decorators import detail_route @@ -8,6 +10,7 @@ from funkwhale_api.music.models import Track from funkwhale_api.common import permissions from funkwhale_api.common import fields +from . import filters from . import models from . import serializers @@ -21,13 +24,17 @@ class PlaylistViewSet( viewsets.GenericViewSet): serializer_class = serializers.PlaylistSerializer - queryset = (models.Playlist.objects.all()) + queryset = ( + models.Playlist.objects.all() + .annotate(tracks_count=Count('playlist_tracks')) + ) permission_classes = [ permissions.ConditionalAuthentication, permissions.OwnerPermission, IsAuthenticatedOrReadOnly, ] owner_checks = ['write'] + filter_class = filters.PlaylistFilter @detail_route(methods=['get']) def tracks(self, request, *args, **kwargs): diff --git a/api/tests/playlists/test_models.py b/api/tests/playlists/test_models.py index dfe40187d..da3e23e28 100644 --- a/api/tests/playlists/test_models.py +++ b/api/tests/playlists/test_models.py @@ -5,6 +5,7 @@ from django import forms def test_can_insert_plt(factories): plt = factories['playlists.PlaylistTrack']() + modification_date = plt.playlist.modification_date assert plt.index is None @@ -12,6 +13,7 @@ def test_can_insert_plt(factories): plt.refresh_from_db() assert plt.index == 0 + assert plt.playlist.modification_date > modification_date def test_insert_use_last_idx_by_default(factories): diff --git a/api/tests/playlists/test_views.py b/api/tests/playlists/test_views.py index 192aad382..03babfabb 100644 --- a/api/tests/playlists/test_views.py +++ b/api/tests/playlists/test_views.py @@ -23,6 +23,16 @@ def test_can_create_playlist_via_api(logged_in_api_client): assert playlist.privacy_level == 'everyone' +def test_serializer_includes_tracks_count(factories, logged_in_api_client): + playlist = factories['playlists.Playlist']() + plt = factories['playlists.PlaylistTrack'](playlist=playlist) + + url = reverse('api:v1:playlists-detail', kwargs={'pk': playlist.pk}) + response = logged_in_api_client.get(url) + + assert response.data['tracks_count'] == 1 + + def test_playlist_inherits_user_privacy(logged_in_api_client): url = reverse('api:v1:playlists-list') user = logged_in_api_client.user From f917c5d0c4293cb0d7eb3cb4443e01cf0764e473 Mon Sep 17 00:00:00 2001 From: Eliot Berriot Date: Mon, 19 Mar 2018 19:07:52 +0100 Subject: [PATCH 45/69] Playlist filterset --- api/funkwhale_api/playlists/filters.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 api/funkwhale_api/playlists/filters.py diff --git a/api/funkwhale_api/playlists/filters.py b/api/funkwhale_api/playlists/filters.py new file mode 100644 index 000000000..cf8e7dd21 --- /dev/null +++ b/api/funkwhale_api/playlists/filters.py @@ -0,0 +1,13 @@ +from django_filters import rest_framework as filters + +from . import models + + + +class PlaylistFilter(filters.FilterSet): + + class Meta: + model = models.Playlist + fields = { + 'user': ['exact'], + } From 8ff775a126d22da6e96ac6a6a13a1ba038034d0a Mon Sep 17 00:00:00 2001 From: Eliot Berriot Date: Tue, 20 Mar 2018 14:36:35 +0100 Subject: [PATCH 46/69] Added tracks count and sort by modification date in front --- front/src/components/playlists/PlaylistModal.vue | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/front/src/components/playlists/PlaylistModal.vue b/front/src/components/playlists/PlaylistModal.vue index 2e1627001..7bf027db7 100644 --- a/front/src/components/playlists/PlaylistModal.vue +++ b/front/src/components/playlists/PlaylistModal.vue @@ -18,7 +18,8 @@
{{ playlist.name }}
- 45 tracks + {{ playlist.tracks_count }} tracks + Last modification {{ playlist.modification_date | ago}}
@@ -34,6 +35,7 @@ + + + diff --git a/front/src/components/audio/track/Table.vue b/front/src/components/audio/track/Table.vue index 00bcf9f7d..512ba1b49 100644 --- a/front/src/components/audio/track/Table.vue +++ b/front/src/components/audio/track/Table.vue @@ -11,34 +11,11 @@
- - - - - - - - + @@ -83,9 +60,8 @@ curl -G -o "{{ track.files[0].filename }}" + + + + + diff --git a/front/src/router/index.js b/front/src/router/index.js index ba9aadd98..31bd0805c 100644 --- a/front/src/router/index.js +++ b/front/src/router/index.js @@ -21,7 +21,7 @@ import RadioBuilder from '@/components/library/radios/Builder' import BatchList from '@/components/library/import/BatchList' import BatchDetail from '@/components/library/import/BatchDetail' import RequestsList from '@/components/requests/RequestsList' - +import PlaylistDetail from '@/views/playlists/Detail' import Favorites from '@/components/favorites/List' Vue.use(Router) @@ -110,6 +110,7 @@ export default new Router({ }, { path: 'radios/build', name: 'library.radios.build', component: RadioBuilder, props: true }, { path: 'radios/build/:id', name: 'library.radios.edit', component: RadioBuilder, props: true }, + { path: 'playlists/:id', name: 'library.playlists.detail', component: PlaylistDetail, props: true }, { path: 'artists/:id', name: 'library.artists.detail', component: LibraryArtist, props: true }, { path: 'albums/:id', name: 'library.albums.detail', component: LibraryAlbum, props: true }, { path: 'tracks/:id', name: 'library.tracks.detail', component: LibraryTrack, props: true }, diff --git a/front/src/views/playlists/Detail.vue b/front/src/views/playlists/Detail.vue new file mode 100644 index 000000000..fc27b7126 --- /dev/null +++ b/front/src/views/playlists/Detail.vue @@ -0,0 +1,88 @@ + + From dd40a4c4d18143bc7f9fc567ccf118fa8078c8b1 Mon Sep 17 00:00:00 2001 From: Eliot Berriot Date: Tue, 20 Mar 2018 19:58:38 +0100 Subject: [PATCH 54/69] Cleanup --- front/src/components/Pagination.vue | 1 - front/src/components/playlists/Form.vue | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/front/src/components/Pagination.vue b/front/src/components/Pagination.vue index 57ae4235d..47cf5183a 100644 --- a/front/src/components/Pagination.vue +++ b/front/src/components/Pagination.vue @@ -64,7 +64,6 @@ export default { } } }) - console.log(final) return final }, maxPage: function () { diff --git a/front/src/components/playlists/Form.vue b/front/src/components/playlists/Form.vue index 8b39c6f6c..267e2c10e 100644 --- a/front/src/components/playlists/Form.vue +++ b/front/src/components/playlists/Form.vue @@ -74,6 +74,7 @@ export default { logger.default.info('Successfully created playlist') self.success = true self.isLoading = false + self.name = '' self.$store.dispatch('playlists/fetchOwn') }, error => { logger.default.error('Error while creating playlist') From 16f631af1a379e6e52888278d433611e5f9e1e3d Mon Sep 17 00:00:00 2001 From: Eliot Berriot Date: Tue, 20 Mar 2018 22:44:28 +0100 Subject: [PATCH 55/69] Performance optimization on playlisttrack serialization --- api/funkwhale_api/playlists/models.py | 11 +++++++++++ api/funkwhale_api/playlists/views.py | 7 +++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/api/funkwhale_api/playlists/models.py b/api/funkwhale_api/playlists/models.py index ed4307b67..6bb8fe178 100644 --- a/api/funkwhale_api/playlists/models.py +++ b/api/funkwhale_api/playlists/models.py @@ -94,6 +94,15 @@ class Playlist(models.Model): ] return PlaylistTrack.objects.bulk_create(plts) +class PlaylistTrackQuerySet(models.QuerySet): + def for_nested_serialization(self): + return (self.select_related() + .select_related('track__album__artist') + .prefetch_related( + 'track__tags', + 'track__files', + 'track__artist__albums__tracks__tags')) + class PlaylistTrack(models.Model): track = models.ForeignKey( @@ -105,6 +114,8 @@ class PlaylistTrack(models.Model): Playlist, related_name='playlist_tracks', on_delete=models.CASCADE) creation_date = models.DateTimeField(default=timezone.now) + objects = PlaylistTrackQuerySet.as_manager() + class Meta: ordering = ('-playlist', 'index') unique_together = ('playlist', 'index') diff --git a/api/funkwhale_api/playlists/views.py b/api/funkwhale_api/playlists/views.py index a077dec27..5de6067ff 100644 --- a/api/funkwhale_api/playlists/views.py +++ b/api/funkwhale_api/playlists/views.py @@ -46,7 +46,7 @@ class PlaylistViewSet( @detail_route(methods=['get']) def tracks(self, request, *args, **kwargs): playlist = self.get_object() - plts = playlist.playlist_tracks.all() + plts = playlist.playlist_tracks.all().for_nested_serialization() serializer = serializers.PlaylistTrackSerializer(plts, many=True) data = { 'count': len(plts), @@ -65,6 +65,9 @@ class PlaylistViewSet( except exceptions.ValidationError as e: payload = {'playlist': e.detail} return Response(payload, status=400) + ids = [p.id for p in plts] + plts = models.PlaylistTrack.objects.filter( + pk__in=ids).order_by('index').for_nested_serialization() serializer = serializers.PlaylistTrackSerializer(plts, many=True) data = { 'count': len(plts), @@ -93,7 +96,7 @@ class PlaylistTrackViewSet( viewsets.GenericViewSet): serializer_class = serializers.PlaylistTrackSerializer - queryset = (models.PlaylistTrack.objects.all()) + queryset = (models.PlaylistTrack.objects.all().for_nested_serialization()) permission_classes = [ permissions.ConditionalAuthentication, permissions.OwnerPermission, From 32dc18ed6e677333bf60060d8d4c24b50c003005 Mon Sep 17 00:00:00 2001 From: Eliot Berriot Date: Tue, 20 Mar 2018 23:39:23 +0100 Subject: [PATCH 56/69] Added dangerous-button component, smarter modal --- .../src/components/common/DangerousButton.vue | 44 +++++++++++++++++++ front/src/components/globals.js | 4 ++ front/src/components/semantic/Modal.vue | 40 +++++++++++------ 3 files changed, 74 insertions(+), 14 deletions(-) create mode 100644 front/src/components/common/DangerousButton.vue diff --git a/front/src/components/common/DangerousButton.vue b/front/src/components/common/DangerousButton.vue new file mode 100644 index 000000000..03a579d29 --- /dev/null +++ b/front/src/components/common/DangerousButton.vue @@ -0,0 +1,44 @@ + + diff --git a/front/src/components/globals.js b/front/src/components/globals.js index b1d7d6104..79bbcf1b9 100644 --- a/front/src/components/globals.js +++ b/front/src/components/globals.js @@ -8,4 +8,8 @@ import Username from '@/components/common/Username' Vue.component('username', Username) +import DangerousButton from '@/components/common/DangerousButton' + +Vue.component('dangerous-button', DangerousButton) + export default {} diff --git a/front/src/components/semantic/Modal.vue b/front/src/components/semantic/Modal.vue index ec7a5a088..fec8fdd05 100644 --- a/front/src/components/semantic/Modal.vue +++ b/front/src/components/semantic/Modal.vue @@ -2,7 +2,7 @@
- +
@@ -19,26 +19,38 @@ export default { control: null } }, - mounted () { - this.control = $(this.$el).modal({ - onApprove: function () { - this.$emit('approved') - }.bind(this), - onDeny: function () { - this.$emit('deny') - }.bind(this), - onHidden: function () { - this.$emit('update:show', false) - }.bind(this) - }) + beforeDestroy () { + if (this.control) { + this.control.remove() + } + }, + methods: { + initModal () { + this.control = $(this.$el).modal({ + duration: 100, + onApprove: function () { + this.$emit('approved') + }.bind(this), + onDeny: function () { + this.$emit('deny') + }.bind(this), + onHidden: function () { + this.$emit('update:show', false) + }.bind(this) + }) + } }, watch: { show: { handler (newValue) { if (newValue) { + this.initModal() this.control.modal('show') } else { - this.control.modal('hide') + if (this.control) { + this.control.modal('hide') + this.control.remove() + } } } } From 053fc1171b98ee95738806e4f1da48f088ab52da Mon Sep 17 00:00:00 2001 From: Eliot Berriot Date: Tue, 20 Mar 2018 23:40:11 +0100 Subject: [PATCH 57/69] Renamed playlist icon class --- front/src/components/audio/track/Row.vue | 8 +++++--- front/src/components/playlists/TrackPlaylistIcon.vue | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/front/src/components/audio/track/Row.vue b/front/src/components/audio/track/Row.vue index 4eda9955a..8310e89c4 100644 --- a/front/src/components/audio/track/Row.vue +++ b/front/src/components/audio/track/Row.vue @@ -60,9 +60,11 @@ export default { - diff --git a/front/src/components/playlists/TrackPlaylistIcon.vue b/front/src/components/playlists/TrackPlaylistIcon.vue index 843d15392..bba4c515b 100644 --- a/front/src/components/playlists/TrackPlaylistIcon.vue +++ b/front/src/components/playlists/TrackPlaylistIcon.vue @@ -9,7 +9,7 @@ From a38f64852fdf0c37017674684ff6fb5c4b94e2ff Mon Sep 17 00:00:00 2001 From: Eliot Berriot Date: Tue, 20 Mar 2018 23:41:15 +0100 Subject: [PATCH 58/69] Can now delete playlist --- .../components/playlists/PlaylistModal.vue | 108 ++++++++++-------- front/src/views/playlists/Detail.vue | 32 +++++- 2 files changed, 91 insertions(+), 49 deletions(-) diff --git a/front/src/components/playlists/PlaylistModal.vue b/front/src/components/playlists/PlaylistModal.vue index b470eb5ce..5fdf585df 100644 --- a/front/src/components/playlists/PlaylistModal.vue +++ b/front/src/components/playlists/PlaylistModal.vue @@ -1,53 +1,66 @@ @@ -100,6 +113,11 @@ export default { p.reverse() return p } + }, + watch: { + '$store.state.route.path' () { + this.$store.commit('playlists/showModal', false) + } } } diff --git a/front/src/views/playlists/Detail.vue b/front/src/views/playlists/Detail.vue index fc27b7126..1f3caa494 100644 --- a/front/src/views/playlists/Detail.vue +++ b/front/src/views/playlists/Detail.vue @@ -1,6 +1,9 @@ + + + diff --git a/front/src/components/playlists/CardList.vue b/front/src/components/playlists/CardList.vue new file mode 100644 index 000000000..4d4746090 --- /dev/null +++ b/front/src/components/playlists/CardList.vue @@ -0,0 +1,34 @@ + + + + + + diff --git a/front/src/components/playlists/Form.vue b/front/src/components/playlists/Form.vue index 267e2c10e..21ddfeaec 100644 --- a/front/src/components/playlists/Form.vue +++ b/front/src/components/playlists/Form.vue @@ -21,8 +21,11 @@ +
+ + +
- diff --git a/front/src/router/index.js b/front/src/router/index.js index 7cffb6f99..802844461 100644 --- a/front/src/router/index.js +++ b/front/src/router/index.js @@ -22,6 +22,7 @@ import BatchList from '@/components/library/import/BatchList' import BatchDetail from '@/components/library/import/BatchDetail' import RequestsList from '@/components/requests/RequestsList' import PlaylistDetail from '@/views/playlists/Detail' +import PlaylistList from '@/views/playlists/List' import Favorites from '@/components/favorites/List' Vue.use(Router) @@ -110,6 +111,17 @@ export default new Router({ }, { path: 'radios/build', name: 'library.radios.build', component: RadioBuilder, props: true }, { path: 'radios/build/:id', name: 'library.radios.edit', component: RadioBuilder, props: true }, + { + path: 'playlists/', + name: 'library.playlists.browse', + component: PlaylistList, + props: (route) => ({ + defaultOrdering: route.query.ordering, + defaultQuery: route.query.query, + defaultPaginateBy: route.query.paginateBy, + defaultPage: route.query.page + }) + }, { path: 'playlists/:id', name: 'library.playlists.detail', diff --git a/front/src/views/playlists/Detail.vue b/front/src/views/playlists/Detail.vue index 1f3caa494..52c38b618 100644 --- a/front/src/views/playlists/Detail.vue +++ b/front/src/views/playlists/Detail.vue @@ -34,7 +34,7 @@ -
+
diff --git a/front/src/views/playlists/List.vue b/front/src/views/playlists/List.vue new file mode 100644 index 000000000..fc5dcbe54 --- /dev/null +++ b/front/src/views/playlists/List.vue @@ -0,0 +1,158 @@ + + + + + + From 6a9a34d244ddc4c4298e5c5364bb214f420691cf Mon Sep 17 00:00:00 2001 From: Eliot Berriot Date: Wed, 21 Mar 2018 12:19:07 +0100 Subject: [PATCH 63/69] Can now clear playlist --- api/funkwhale_api/playlists/views.py | 8 ++++++ api/tests/playlists/test_views.py | 12 ++++++++ .../src/components/common/DangerousButton.vue | 10 +++++-- front/src/components/playlists/Editor.vue | 28 +++++++++++++++++-- 4 files changed, 52 insertions(+), 6 deletions(-) diff --git a/api/funkwhale_api/playlists/views.py b/api/funkwhale_api/playlists/views.py index 4880b1886..7b2e7651d 100644 --- a/api/funkwhale_api/playlists/views.py +++ b/api/funkwhale_api/playlists/views.py @@ -75,6 +75,14 @@ class PlaylistViewSet( } return Response(data, status=201) + @detail_route(methods=['delete']) + @transaction.atomic + def clear(self, request, *args, **kwargs): + playlist = self.get_object() + playlist.playlist_tracks.all().delete() + playlist.save(update_fields=['modification_date']) + return Response(status=204) + def get_queryset(self): return self.queryset.filter( fields.privacy_level_query(self.request.user)) diff --git a/api/tests/playlists/test_views.py b/api/tests/playlists/test_views.py index ae3fd0074..e70fef6f0 100644 --- a/api/tests/playlists/test_views.py +++ b/api/tests/playlists/test_views.py @@ -170,3 +170,15 @@ def test_can_add_multiple_tracks_at_once_via_api( for plt in playlist.playlist_tracks.order_by('index'): assert response.data['results'][plt.index]['id'] == plt.id assert plt.track == tracks[plt.index] + + +def test_can_clear_playlist_from_api( + factories, mocker, logged_in_api_client): + playlist = factories['playlists.Playlist'](user=logged_in_api_client.user) + plts = factories['playlists.PlaylistTrack'].create_batch( + size=5, playlist=playlist) + url = reverse('api:v1:playlists-clear', kwargs={'pk': playlist.pk}) + response = logged_in_api_client.delete(url) + + assert response.status_code == 204 + assert playlist.playlist_tracks.count() == 0 diff --git a/front/src/components/common/DangerousButton.vue b/front/src/components/common/DangerousButton.vue index 03a579d29..525b4c48f 100644 --- a/front/src/components/common/DangerousButton.vue +++ b/front/src/components/common/DangerousButton.vue @@ -1,5 +1,5 @@
- - - - - - - - {{ track.title }} - - - - {{ track.artist.name }} - - - - {{ track.album.title }} - -