From 08b28a7d9864f6fec0f01df4c33b772f42cfb9aa Mon Sep 17 00:00:00 2001
From: Eliot Berriot <contact@eliotberriot.com>
Date: Mon, 19 Mar 2018 19:07:45 +0100
Subject: [PATCH] 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 00000000..f4a52529
--- /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 d8c90aef..f26dbeff 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 43e2414d..0680dc8d 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 02e53cb1..dc3475fa 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 dfe40187..da3e23e2 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 192aad38..03babfab 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
-- 
GitLab