Commit 20eaa5e6 authored by Eliot Berriot's avatar Eliot Berriot

Merge branch 'release/0.2.5'

parents 142a8050 5ac9d261
......@@ -13,14 +13,22 @@ stages:
test_api:
stage: test
image: funkwhale/funkwhale:base
variables:
PIP_CACHE_DIR: "$CI_PROJECT_DIR/pip-cache"
DATABASE_URL: "sqlite://"
before_script:
- python3 -m venv --copies virtualenv
- source virtualenv/bin/activate
- cd api
- pip install -r requirements/base.txt
- pip install -r requirements/local.txt
- pip install -r requirements/test.txt
script:
- pytest
variables:
DATABASE_URL: "sqlite://"
cache:
key: "$CI_JOB_NAME-$CI_COMMIT_REF_NAME"
paths:
- "$CI_PROJECT_DIR/pip-cache"
tags:
- docker
......
......@@ -2,10 +2,30 @@ Changelog
=========
0.2.5 (unreleased)
0.2.6 (Unreleased)
------------------
0.2.5 (2017-12-15)
------------------
Features:
- Import: can now specify search template when querying import sources (#45)
- Login form: now redirect to previous page after login (#2)
- 404: a decent 404 template, at least (#48)
Bugfixes:
- Player: better handling of errors when fetching the audio file (#46)
- Csrf: default CSRF_TRUSTED_ORIGINS to ALLOWED_HOSTS to avoid Csrf issues on admin (#49)
Tech:
- Django 2 compatibility, lot of packages upgrades (#47)
0.2.4 (2017-12-14)
------------------
......
......@@ -8,7 +8,9 @@ COPY ./requirements.apt /requirements.apt
RUN apt-get update -qq && grep "^[^#;]" requirements.apt | xargs apt-get install -y
COPY ./requirements /requirements
COPY ./requirements/base.txt /requirements
RUN pip install -r /requirements/base.txt
COPY ./requirements/production.txt /requirements
RUN pip install -r /requirements/production.txt
COPY . /app
......
......@@ -25,22 +25,32 @@ v1_patterns = router.urls
v1_patterns += [
url(r'^providers/',
include('funkwhale_api.providers.urls', namespace='providers')),
include(
('funkwhale_api.providers.urls', 'providers'),
namespace='providers')),
url(r'^favorites/',
include('funkwhale_api.favorites.urls', namespace='favorites')),
include(
('funkwhale_api.favorites.urls', 'favorites'),
namespace='favorites')),
url(r'^search$',
views.Search.as_view(), name='search'),
url(r'^radios/',
include('funkwhale_api.radios.urls', namespace='radios')),
include(
('funkwhale_api.radios.urls', 'radios'),
namespace='radios')),
url(r'^history/',
include('funkwhale_api.history.urls', namespace='history')),
include(
('funkwhale_api.history.urls', 'history'),
namespace='history')),
url(r'^users/',
include('funkwhale_api.users.api_urls', namespace='users')),
include(
('funkwhale_api.users.api_urls', 'users'),
namespace='users')),
url(r'^token/',
jwt_views.obtain_jwt_token),
url(r'^token/refresh/', jwt_views.refresh_jwt_token),
]
urlpatterns = [
url(r'^v1/', include(v1_patterns, namespace='v1'))
url(r'^v1/', include((v1_patterns, 'v1'), namespace='v1'))
]
......@@ -75,7 +75,7 @@ INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS
# MIDDLEWARE CONFIGURATION
# ------------------------------------------------------------------------------
MIDDLEWARE_CLASSES = (
MIDDLEWARE = (
# Make sure djangosecure.middleware.SecurityMiddleware is listed first
'django.contrib.sessions.middleware.SessionMiddleware',
'funkwhale_api.users.middleware.AnonymousSessionMiddleware',
......
......@@ -31,7 +31,7 @@ EMAIL_BACKEND = env('DJANGO_EMAIL_BACKEND',
# django-debug-toolbar
# ------------------------------------------------------------------------------
MIDDLEWARE_CLASSES += ('debug_toolbar.middleware.DebugToolbarMiddleware',)
MIDDLEWARE += ('debug_toolbar.middleware.DebugToolbarMiddleware',)
# INTERNAL_IPS = ('127.0.0.1', '10.0.2.2',)
......
......@@ -36,7 +36,7 @@ SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
#
#
# # Make sure djangosecure.middleware.SecurityMiddleware is listed first
# MIDDLEWARE_CLASSES = SECURITY_MIDDLEWARE + MIDDLEWARE_CLASSES
# MIDDLEWARE = SECURITY_MIDDLEWARE + MIDDLEWARE
#
# # set this to 60 seconds and then to 518400 when you can prove it works
# SECURE_HSTS_SECONDS = 60
......@@ -55,6 +55,8 @@ SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
# Hosts/domain names that are valid for this site
# See https://docs.djangoproject.com/en/1.6/ref/settings/#allowed-hosts
ALLOWED_HOSTS = env.list('DJANGO_ALLOWED_HOSTS')
CSRF_TRUSTED_ORIGINS = ALLOWED_HOSTS
# END SITE CONFIGURATION
INSTALLED_APPS += ("gunicorn", )
......
......@@ -22,8 +22,8 @@ CACHES = {
'LOCATION': ''
}
}
INSTALLED_APPS += ('kombu.transport.django',)
BROKER_URL = 'django://'
BROKER_URL = 'memory://'
# TESTING
# ------------------------------------------------------------------------------
......
......@@ -10,9 +10,9 @@ from django.views import defaults as default_views
urlpatterns = [
# Django Admin, use {% url 'admin:index' %}
url(settings.ADMIN_URL, include(admin.site.urls)),
url(settings.ADMIN_URL, admin.site.urls),
url(r'^api/', include("config.api_urls", namespace="api")),
url(r'^api/', include(("config.api_urls", 'api'), namespace="api")),
url(r'^api/auth/', include('rest_auth.urls')),
url(r'^api/auth/registration/', include('funkwhale_api.users.rest_auth_urls')),
url(r'^accounts/', include('allauth.urls')),
......
# -*- coding: utf-8 -*-
__version__ = '0.2.4'
__version__ = '0.2.5'
__version_info__ = tuple([int(num) if num.isdigit() else num for num in __version__.replace('-', '.', 1).split('.')])
......@@ -7,5 +7,5 @@ class ConditionalAuthentication(BasePermission):
def has_permission(self, request, view):
if settings.API_AUTHENTICATION_REQUIRED:
return request.user and request.user.is_authenticated()
return request.user and request.user.is_authenticated
return True
......@@ -25,7 +25,7 @@ class Migration(migrations.Migration):
'ordering': ('domain',),
},
managers=[
(b'objects', django.contrib.sites.models.SiteManager()),
('objects', django.contrib.sites.models.SiteManager()),
],
),
]
......@@ -19,8 +19,8 @@ class Migration(migrations.Migration):
fields=[
('id', models.AutoField(serialize=False, auto_created=True, verbose_name='ID', primary_key=True)),
('creation_date', models.DateTimeField(default=django.utils.timezone.now)),
('track', models.ForeignKey(related_name='track_favorites', to='music.Track')),
('user', models.ForeignKey(related_name='track_favorites', to=settings.AUTH_USER_MODEL)),
('track', models.ForeignKey(related_name='track_favorites', to='music.Track', on_delete=models.CASCADE)),
('user', models.ForeignKey(related_name='track_favorites', to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE)),
],
options={
'ordering': ('-creation_date',),
......
......@@ -5,8 +5,10 @@ from funkwhale_api.music.models import Track
class TrackFavorite(models.Model):
creation_date = models.DateTimeField(default=timezone.now)
user = models.ForeignKey('users.User', related_name='track_favorites')
track = models.ForeignKey(Track, related_name='track_favorites')
user = models.ForeignKey(
'users.User', related_name='track_favorites', on_delete=models.CASCADE)
track = models.ForeignKey(
Track, related_name='track_favorites', on_delete=models.CASCADE)
class Meta:
unique_together = ('track', 'user')
......
import json
from test_plus.test import TestCase
from django.core.urlresolvers import reverse
from django.urls import reverse
from funkwhale_api.music.models import Track, Artist
from funkwhale_api.favorites.models import TrackFavorite
......
......@@ -20,8 +20,8 @@ class Migration(migrations.Migration):
('id', models.AutoField(verbose_name='ID', primary_key=True, serialize=False, auto_created=True)),
('end_date', models.DateTimeField(null=True, blank=True, default=django.utils.timezone.now)),
('session_key', models.CharField(null=True, blank=True, max_length=100)),
('track', models.ForeignKey(related_name='listenings', to='music.Track')),
('user', models.ForeignKey(blank=True, null=True, related_name='listenings', to=settings.AUTH_USER_MODEL)),
('track', models.ForeignKey(related_name='listenings', to='music.Track', on_delete=models.CASCADE)),
('user', models.ForeignKey(blank=True, null=True, related_name='listenings', to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE)),
],
options={
'ordering': ('-end_date',),
......
......@@ -7,8 +7,14 @@ from funkwhale_api.music.models import Track
class Listening(models.Model):
end_date = models.DateTimeField(default=timezone.now, null=True, blank=True)
track = models.ForeignKey(Track, related_name="listenings")
user = models.ForeignKey('users.User', related_name="listenings", null=True, blank=True)
track = models.ForeignKey(
Track, related_name="listenings", on_delete=models.CASCADE)
user = models.ForeignKey(
'users.User',
related_name="listenings",
null=True,
blank=True,
on_delete=models.CASCADE)
session_key = models.CharField(max_length=100, null=True, blank=True)
class Meta:
......
import factory
from funkwhale_api.music.tests import factories
from funkwhale_api.users.tests.factories import UserFactory
class ListeningFactory(factory.django.DjangoModelFactory):
user = factory.SubFactory(UserFactory)
track = factory.SubFactory(factories.TrackFactory)
class Meta:
model = 'history.Listening'
import random
import json
from test_plus.test import TestCase
from django.core.urlresolvers import reverse
from django.urls import reverse
from django.core.exceptions import ValidationError
from django.utils import timezone
from model_mommy import mommy
from funkwhale_api.music.tests.factories import TrackFactory
from funkwhale_api.users.models import User
from funkwhale_api.history import models
class TestHistory(TestCase):
def setUp(self):
......@@ -17,12 +18,12 @@ class TestHistory(TestCase):
self.user = User.objects.create_user(username='test', email='test@test.com', password='test')
def test_can_create_listening(self):
track = mommy.make('music.Track')
track = TrackFactory()
now = timezone.now()
l = models.Listening.objects.create(user=self.user, track=track)
def test_anonymous_user_can_create_listening_via_api(self):
track = mommy.make('music.Track')
track = TrackFactory()
url = self.reverse('api:v1:history:listenings-list')
response = self.client.post(url, {
'track': track.pk,
......@@ -34,7 +35,7 @@ class TestHistory(TestCase):
self.assertIsNotNone(listening.session_key)
def test_logged_in_user_can_create_listening_via_api(self):
track = mommy.make('music.Track')
track = TrackFactory()
self.client.login(username=self.user.username, password='test')
......
......@@ -22,14 +22,14 @@ class ListeningViewSet(mixins.CreateModelMixin,
def get_queryset(self):
queryset = super().get_queryset()
if self.request.user.is_authenticated():
if self.request.user.is_authenticated:
return queryset.filter(user=self.request.user)
else:
return queryset.filter(session_key=self.request.session.session_key)
def get_serializer_context(self):
context = super().get_serializer_context()
if self.request.user.is_authenticated():
if self.request.user.is_authenticated:
context['user'] = self.request.user
else:
context['session_key'] = self.request.session.session_key
......
......@@ -44,7 +44,7 @@ class Migration(migrations.Migration):
fields=[
('id', models.AutoField(primary_key=True, auto_created=True, serialize=False, verbose_name='ID')),
('creation_date', models.DateTimeField(default=django.utils.timezone.now)),
('submitted_by', models.ForeignKey(related_name='imports', to=settings.AUTH_USER_MODEL)),
('submitted_by', models.ForeignKey(related_name='imports', to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE)),
],
),
migrations.CreateModel(
......@@ -54,7 +54,7 @@ class Migration(migrations.Migration):
('source', models.URLField()),
('mbid', models.UUIDField(editable=False)),
('status', models.CharField(default='pending', choices=[('pending', 'Pending'), ('finished', 'finished')], max_length=30)),
('batch', models.ForeignKey(related_name='jobs', to='music.ImportBatch')),
('batch', models.ForeignKey(related_name='jobs', to='music.ImportBatch', on_delete=models.CASCADE)),
],
),
migrations.CreateModel(
......@@ -64,8 +64,8 @@ class Migration(migrations.Migration):
('mbid', models.UUIDField(editable=False, blank=True, null=True)),
('creation_date', models.DateTimeField(default=django.utils.timezone.now)),
('title', models.CharField(max_length=255)),
('album', models.ForeignKey(related_name='tracks', blank=True, null=True, to='music.Album')),
('artist', models.ForeignKey(related_name='tracks', to='music.Artist')),
('album', models.ForeignKey(related_name='tracks', blank=True, null=True, to='music.Album', on_delete=models.CASCADE)),
('artist', models.ForeignKey(related_name='tracks', to='music.Artist', on_delete=models.CASCADE)),
],
options={
'abstract': False,
......@@ -78,12 +78,12 @@ class Migration(migrations.Migration):
('audio_file', models.FileField(upload_to='tracks')),
('source', models.URLField(blank=True, null=True)),
('duration', models.IntegerField(blank=True, null=True)),
('track', models.ForeignKey(related_name='files', to='music.Track')),
('track', models.ForeignKey(related_name='files', to='music.Track', on_delete=models.CASCADE)),
],
),
migrations.AddField(
model_name='album',
name='artist',
field=models.ForeignKey(related_name='albums', to='music.Artist'),
field=models.ForeignKey(related_name='albums', to='music.Artist', on_delete=models.CASCADE),
),
]
......@@ -39,11 +39,11 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='lyrics',
name='work',
field=models.ForeignKey(related_name='lyrics', to='music.Work', blank=True, null=True),
field=models.ForeignKey(related_name='lyrics', to='music.Work', blank=True, null=True, on_delete=models.CASCADE),
),
migrations.AddField(
model_name='track',
name='work',
field=models.ForeignKey(related_name='tracks', to='music.Work', blank=True, null=True),
field=models.ForeignKey(related_name='tracks', to='music.Work', blank=True, null=True, on_delete=models.CASCADE),
),
]
......@@ -10,7 +10,7 @@ from django.conf import settings
from django.db import models
from django.core.files.base import ContentFile
from django.core.files import File
from django.core.urlresolvers import reverse
from django.urls import reverse
from django.utils import timezone
from taggit.managers import TaggableManager
from versatileimagefield.fields import VersatileImageField
......@@ -108,7 +108,8 @@ def import_tracks(instance, cleaned_data, raw_data):
class Album(APIModelMixin):
title = models.CharField(max_length=255)
artist = models.ForeignKey(Artist, related_name='albums')
artist = models.ForeignKey(
Artist, related_name='albums', on_delete=models.CASCADE)
release_date = models.DateField(null=True)
release_group_id = models.UUIDField(null=True, blank=True)
cover = VersatileImageField(upload_to='albums/covers/%Y/%m/%d', null=True, blank=True)
......@@ -245,7 +246,12 @@ class Work(APIModelMixin):
class Lyrics(models.Model):
work = models.ForeignKey(Work, related_name='lyrics', null=True, blank=True)
work = models.ForeignKey(
Work,
related_name='lyrics',
null=True,
blank=True,
on_delete=models.CASCADE)
url = models.URLField(unique=True)
content = models.TextField(null=True, blank=True)
......@@ -268,10 +274,21 @@ class Lyrics(models.Model):
class Track(APIModelMixin):
title = models.CharField(max_length=255)
artist = models.ForeignKey(Artist, related_name='tracks')
artist = models.ForeignKey(
Artist, related_name='tracks', on_delete=models.CASCADE)
position = models.PositiveIntegerField(null=True, blank=True)
album = models.ForeignKey(Album, related_name='tracks', null=True, blank=True)
work = models.ForeignKey(Work, related_name='tracks', null=True, blank=True)
album = models.ForeignKey(
Album,
related_name='tracks',
null=True,
blank=True,
on_delete=models.CASCADE)
work = models.ForeignKey(
Work,
related_name='tracks',
null=True,
blank=True,
on_delete=models.CASCADE)
musicbrainz_model = 'recording'
api = musicbrainz.api.recordings
......@@ -340,7 +357,8 @@ class Track(APIModelMixin):
class TrackFile(models.Model):
track = models.ForeignKey(Track, related_name='files')
track = models.ForeignKey(
Track, related_name='files', on_delete=models.CASCADE)
audio_file = models.FileField(upload_to='tracks/%Y/%m/%d', max_length=255)
source = models.URLField(null=True, blank=True)
duration = models.IntegerField(null=True, blank=True)
......@@ -376,7 +394,8 @@ class TrackFile(models.Model):
class ImportBatch(models.Model):
creation_date = models.DateTimeField(default=timezone.now)
submitted_by = models.ForeignKey('users.User', related_name='imports')
submitted_by = models.ForeignKey(
'users.User', related_name='imports', on_delete=models.CASCADE)
class Meta:
ordering = ['-creation_date']
......@@ -392,9 +411,14 @@ class ImportBatch(models.Model):
return 'finished'
class ImportJob(models.Model):
batch = models.ForeignKey(ImportBatch, related_name='jobs')
batch = models.ForeignKey(
ImportBatch, related_name='jobs', on_delete=models.CASCADE)
track_file = models.ForeignKey(
TrackFile, related_name='jobs', null=True, blank=True)
TrackFile,
related_name='jobs',
null=True,
blank=True,
on_delete=models.CASCADE)
source = models.URLField()
mbid = models.UUIDField(editable=False)
STATUS_CHOICES = (
......
......@@ -59,3 +59,30 @@ class ImportJobFactory(factory.django.DjangoModelFactory):
class Meta:
model = 'music.ImportJob'
class WorkFactory(factory.django.DjangoModelFactory):
mbid = factory.Faker('uuid4')
language = 'eng'
nature = 'song'
title = factory.Faker('sentence', nb_words=3)
class Meta:
model = 'music.Work'
class LyricsFactory(factory.django.DjangoModelFactory):
work = factory.SubFactory(WorkFactory)
url = factory.Faker('url')
content = factory.Faker('paragraphs', nb=4)
class Meta:
model = 'music.Lyrics'
class TagFactory(factory.django.DjangoModelFactory):
name = factory.SelfAttribute('slug')
slug = factory.Faker('slug')
class Meta:
model = 'taggit.Tag'
import json
import unittest
from test_plus.test import TestCase
from django.core.urlresolvers import reverse
from django.urls import reverse
from funkwhale_api.music import models
from funkwhale_api.utils.tests import TMPDirTestCaseMixin
......
import json
import unittest
from test_plus.test import TestCase
from django.core.urlresolvers import reverse
from model_mommy import mommy
from django.urls import reverse
from funkwhale_api.music import models
from funkwhale_api.musicbrainz import api
from funkwhale_api.music import serializers
from funkwhale_api.users.models import User
from funkwhale_api.music import lyrics as lyrics_utils
from .mocking import lyricswiki
from . import factories
from . import data as api_data
from funkwhale_api.music import lyrics as lyrics_utils
class TestLyrics(TestCase):
@unittest.mock.patch('funkwhale_api.music.lyrics._get_html',
return_value=lyricswiki.content)
def test_works_import_lyrics_if_any(self, *mocks):
lyrics = mommy.make(
models.Lyrics,
lyrics = factories.LyricsFactory(
url='http://lyrics.wikia.com/System_Of_A_Down:Chop_Suey!')
lyrics.fetch_content()
......@@ -42,7 +43,7 @@ Is it me you're looking for?
content = """Hello
Is it me you're looking for?"""
l = mommy.make(models.Lyrics, content=content)
l = factories.LyricsFactory(content=content)
expected = "<p>Hello<br />Is it me you're looking for?</p>"
self.assertHTMLEqual(expected, l.content_rendered)
......@@ -54,8 +55,7 @@ Is it me you're looking for?"""
@unittest.mock.patch('funkwhale_api.music.lyrics._get_html',
return_value=lyricswiki.content)
def test_works_import_lyrics_if_any(self, *mocks):
track = mommy.make(
models.Track,
track = factories.TrackFactory(
work=None,
mbid='07ca77cf-f513-4e9c-b190-d7e24bbad448')
......
......@@ -2,13 +2,11 @@ from test_plus.test import TestCase
import unittest.mock
from funkwhale_api.music import models
import datetime
from model_mommy import mommy
from . import factories
from . import data as api_data
from .cover import binary_data
def prettyprint(d):
import json
print(json.dumps(d, sort_keys=True, indent=4))
class TestMusic(TestCase):
......@@ -79,9 +77,9 @@ class TestMusic(TestCase):
self.assertEqual(track, track2)
def test_album_tags_deduced_from_tracks_tags(self):
tag = mommy.make('taggit.Tag')
album = mommy.make('music.Album')
tracks = mommy.make('music.Track', album=album, _quantity=5)
tag = factories.TagFactory()
album = factories.AlbumFactory()
tracks = factories.TrackFactory.create_batch(album=album, size=5)
for track in tracks:
track.tags.add(tag)
......@@ -92,10 +90,10 @@ class TestMusic(TestCase):
self.assertIn(tag, album.tags)
def test_artist_tags_deduced_from_album_tags(self):
tag = mommy.make('taggit.Tag')
artist = mommy.make('music.Artist')
album = mommy.make('music.Album', artist=artist)
tracks = mommy.make('music.Track', album=album, _quantity=5)
tag = factories.TagFactory()
artist = factories.ArtistFactory()
album = factories.AlbumFactory(artist=artist)
tracks = factories.TrackFactory.create_batch(album=album, size=5)
for track in tracks:
track.tags.add(tag)
......@@ -108,7 +106,7 @@ class TestMusic(TestCase):
@unittest.mock.patch('funkwhale_api.musicbrainz.api.images.get_front', return_value=binary_data)
def test_can_download_image_file_for_album(self, *mocks):
# client._api.get_image_front('55ea4f82-b42b-423e-a0e5-290ccdf443ed')
album = mommy.make('music.Album', mbid='55ea4f82-b42b-423e-a0e5-290ccdf443ed')
album = factories.AlbumFactory(mbid='55ea4f82-b42b-423e-a0e5-290ccdf443ed')
album.get_image()
album.save()
......
import json
import unittest
from test_plus.test import TestCase
from django.core.urlresolvers import reverse
from model_mommy import mommy
from django.urls import reverse
from funkwhale_api.music import models
from funkwhale_api.musicbrainz import api
from funkwhale_api.music import serializers
from funkwhale_api.music.tests import factories
from funkwhale_api.users.models import User
from . import data as api_data
class TestWorks(TestCase):
@unittest.mock.patch('funkwhale_api.musicbrainz.api.works.get',
return_value=api_data.works['get']['chop_suey'])
def test_can_import_work(self, *mocks):
recording = mommy.make(
models.Track, mbid='07ca77cf-f513-4e9c-b190-d7e24bbad448')
recording = factories.TrackFactory(
mbid='07ca77cf-f513-4e9c-b190-d7e24bbad448')
mbid = 'e2ecabc4-1b9d-30b2-8f30-3596ec423dc5'
work = models.Work.create_from_api(id=mbid)
......@@ -36,8 +37,7 @@ class TestWorks(TestCase):
@unittest.mock.patch('funkwhale_api.musicbrainz.api.recordings.get',
return_value=api_data.tracks['get']['chop_suey'])
def test_can_get_work_from_recording(self, *mocks):
recording = mommy.make(
models.Track,
recording = factories.TrackFactory(
work=None,
mbid='07ca77cf-f513-4e9c-b190-d7e24bbad448')
mbid = 'e2ecabc4-1b9d-30b2-8f30-3596ec423dc5'
......
......@@ -2,7 +2,7 @@ import os
import json
import unicodedata
import urllib
from django.core.urlresolvers import reverse
from django.urls import reverse
from django.db import models, transaction
from django.db.models.functions import Length
from django.conf import settings
......@@ -102,7 +102,7 @@ class TrackViewSet(TagViewSetMixin, SearchMixin, viewsets.ReadOnlyModelViewSet):
queryset = super().get_queryset()
filter_favorites = self.request.GET.get('favorites', None)
user = self.request.user
if user.is_authenticated() and filter_favorites == 'true':
if user.is_authenticated and filter_favorites == 'true':
queryset = queryset.filter(track_favorites__user=user)
return queryset
......