Merge branch 'release/0.2.5'

merge-requests/154/head 0.2.5
Eliot Berriot 2017-12-16 16:15:40 +01:00
commit 20eaa5e615
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: DD6965E2476E5C27
58 zmienionych plików z 406 dodań i 196 usunięć

Wyświetl plik

@ -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

Wyświetl plik

@ -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)
------------------

Wyświetl plik

@ -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

Wyświetl plik

@ -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'))
]

Wyświetl plik

@ -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',

Wyświetl plik

@ -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',)

Wyświetl plik

@ -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", )

Wyświetl plik

@ -22,8 +22,8 @@ CACHES = {
'LOCATION': ''
}
}
INSTALLED_APPS += ('kombu.transport.django',)
BROKER_URL = 'django://'
BROKER_URL = 'memory://'
# TESTING
# ------------------------------------------------------------------------------

Wyświetl plik

@ -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')),

Wyświetl plik

@ -1,3 +1,3 @@
# -*- 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('.')])

Wyświetl plik

@ -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

Wyświetl plik

@ -25,7 +25,7 @@ class Migration(migrations.Migration):
'ordering': ('domain',),
},
managers=[
(b'objects', django.contrib.sites.models.SiteManager()),
('objects', django.contrib.sites.models.SiteManager()),
],
),
]

Wyświetl plik

@ -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',),

Wyświetl plik

@ -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')

Wyświetl plik

@ -1,6 +1,6 @@
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

Wyświetl plik

@ -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',),

Wyświetl plik

@ -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:

Wyświetl plik

@ -0,0 +1,12 @@
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'

Wyświetl plik

@ -1,15 +1,16 @@
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')

Wyświetl plik

@ -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

Wyświetl plik

@ -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),
),
]

Wyświetl plik

@ -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),
),
]

Wyświetl plik

@ -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 = (

Wyświetl plik

@ -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'

Wyświetl plik

@ -1,7 +1,7 @@
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

Wyświetl plik

@ -1,25 +1,26 @@
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')

Wyświetl plik

@ -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()

Wyświetl plik

@ -1,23 +1,24 @@
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'

Wyświetl plik

@ -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

Wyświetl plik

@ -1,7 +1,7 @@
import json
import unittest
from test_plus.test import TestCase
from django.core.urlresolvers import reverse
from django.urls import reverse
from funkwhale_api.musicbrainz import api
from . import data as api_data

Wyświetl plik

@ -22,7 +22,7 @@ class Migration(migrations.Migration):
('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')),
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL, related_name='playlists', on_delete=models.CASCADE)),
],
),
migrations.CreateModel(
@ -33,9 +33,9 @@ class Migration(migrations.Migration):
('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')),
('playlist', models.ForeignKey(to='playlists.Playlist', related_name='playlist_tracks', on_delete=models.CASCADE)),
('previous', mptt.fields.TreeOneToOneField(null=True, to='playlists.PlaylistTrack', related_name='next', blank=True, on_delete=models.CASCADE)),
('track', models.ForeignKey(to='music.Track', related_name='playlist_tracks', on_delete=models.CASCADE)),
],
options={
'ordering': ('-playlist', 'position'),

Wyświetl plik

@ -7,7 +7,8 @@ from mptt.models import MPTTModel, TreeOneToOneField
class Playlist(models.Model):
name = models.CharField(max_length=50)
is_public = models.BooleanField(default=False)
user = models.ForeignKey('users.User', related_name="playlists")
user = models.ForeignKey(
'users.User', related_name="playlists", on_delete=models.CASCADE)
creation_date = models.DateTimeField(default=timezone.now)
def __str__(self):
@ -21,9 +22,18 @@ class Playlist(models.Model):
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')
track = models.ForeignKey(
'music.Track',
related_name='playlist_tracks',
on_delete=models.CASCADE)
previous = TreeOneToOneField(
'self',
blank=True,
null=True,
related_name='next',
on_delete=models.CASCADE)
playlist = models.ForeignKey(
Playlist, related_name='playlist_tracks', on_delete=models.CASCADE)
class MPTTMeta:
level_attr = 'position'

Wyświetl plik

@ -1,11 +1,10 @@
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 import factories
from funkwhale_api.users.models import User
from funkwhale_api.playlists import models
from funkwhale_api.playlists.serializers import PlaylistSerializer
@ -18,7 +17,7 @@ class TestPlayLists(TestCase):
self.user = User.objects.create_user(username='test', email='test@test.com', password='test')
def test_can_create_playlist(self):
tracks = list(mommy.make('music.Track', _quantity=5))
tracks = factories.TrackFactory.create_batch(size=5)
playlist = models.Playlist.objects.create(user=self.user, name="test")
previous = None
@ -49,7 +48,7 @@ class TestPlayLists(TestCase):
self.assertEqual(playlist.name, 'test')
def test_can_add_playlist_track_via_api(self):
tracks = list(mommy.make('music.Track', _quantity=5))
tracks = factories.TrackFactory.create_batch(size=5)
playlist = models.Playlist.objects.create(user=self.user, name="test")
self.client.login(username=self.user.username, password='test')

Wyświetl plik

@ -1,8 +1,11 @@
from django.conf.urls import include, url
from funkwhale_api.music import views
urlpatterns = [
url(r'^youtube/', include('funkwhale_api.providers.youtube.urls', namespace='youtube')),
url(r'^musicbrainz/', include('funkwhale_api.musicbrainz.urls', namespace='musicbrainz')),
url(r'^youtube/', include(
('funkwhale_api.providers.youtube.urls', 'youtube'),
namespace='youtube')),
url(r'^musicbrainz/', include(
('funkwhale_api.musicbrainz.urls', 'musicbrainz'),
namespace='musicbrainz')),
]

Wyświetl plik

@ -2,7 +2,7 @@ import json
from collections import OrderedDict
import unittest
from test_plus.test import TestCase
from django.core.urlresolvers import reverse
from django.urls import reverse
from funkwhale_api.providers.youtube.client import client
from . import data as api_data

Wyświetl plik

@ -20,7 +20,7 @@ class Migration(migrations.Migration):
('id', models.AutoField(verbose_name='ID', primary_key=True, serialize=False, auto_created=True)),
('radio_type', models.CharField(max_length=50)),
('creation_date', models.DateTimeField(default=django.utils.timezone.now)),
('user', models.ForeignKey(related_name='radio_sessions', blank=True, to=settings.AUTH_USER_MODEL, null=True)),
('user', models.ForeignKey(related_name='radio_sessions', blank=True, to=settings.AUTH_USER_MODEL, null=True, on_delete=models.CASCADE)),
],
),
migrations.CreateModel(
@ -28,8 +28,8 @@ class Migration(migrations.Migration):
fields=[
('id', models.AutoField(verbose_name='ID', primary_key=True, serialize=False, auto_created=True)),
('position', models.IntegerField(default=1)),
('session', models.ForeignKey(to='radios.RadioSession', related_name='session_tracks')),
('track', models.ForeignKey(to='music.Track', related_name='radio_session_tracks')),
('session', models.ForeignKey(to='radios.RadioSession', related_name='session_tracks', on_delete=models.CASCADE)),
('track', models.ForeignKey(to='music.Track', related_name='radio_session_tracks', on_delete=models.CASCADE)),
],
options={
'ordering': ('session', 'position'),

Wyświetl plik

@ -15,7 +15,7 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='radiosession',
name='related_object_content_type',
field=models.ForeignKey(null=True, to='contenttypes.ContentType', blank=True),
field=models.ForeignKey(null=True, to='contenttypes.ContentType', blank=True, on_delete=models.CASCADE),
),
migrations.AddField(
model_name='radiosession',

Wyświetl plik

@ -7,11 +7,20 @@ from django.contrib.contenttypes.models import ContentType
from funkwhale_api.music.models import Track
class RadioSession(models.Model):
user = models.ForeignKey('users.User', related_name='radio_sessions', null=True, blank=True)
user = models.ForeignKey(
'users.User',
related_name='radio_sessions',
null=True,
blank=True,
on_delete=models.CASCADE)
session_key = models.CharField(max_length=100, null=True, blank=True)
radio_type = models.CharField(max_length=50)
creation_date = models.DateTimeField(default=timezone.now)
related_object_content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE, blank=True, null=True)
related_object_content_type = models.ForeignKey(
ContentType,
blank=True,
null=True,
on_delete=models.CASCADE)
related_object_id = models.PositiveIntegerField(blank=True, null=True)
related_object = GenericForeignKey('related_object_content_type', 'related_object_id')
@ -43,9 +52,11 @@ class RadioSession(models.Model):
return registry[self.radio_type](session=self)
class RadioSessionTrack(models.Model):
session = models.ForeignKey(RadioSession, related_name='session_tracks')
session = models.ForeignKey(
RadioSession, related_name='session_tracks', on_delete=models.CASCADE)
position = models.IntegerField(default=1)
track = models.ForeignKey(Track, related_name='radio_session_tracks')
track = models.ForeignKey(
Track, related_name='radio_session_tracks', on_delete=models.CASCADE)
class Meta:
ordering = ('session', 'position')

Wyświetl plik

@ -1,16 +1,18 @@
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 model_mommy import mommy
from funkwhale_api.radios import radios
from funkwhale_api.radios import models
from funkwhale_api.favorites.models import TrackFavorite
from funkwhale_api.users.models import User
from funkwhale_api.music.models import Artist
from funkwhale_api.music.tests import factories
from funkwhale_api.history.tests.factories import ListeningFactory
class TestRadios(TestCase):
@ -55,7 +57,7 @@ class TestRadios(TestCase):
self.assertTrue(picks[2] > picks[1])
def test_can_get_choices_for_favorites_radio(self):
tracks = mommy.make('music.Track', _quantity=100)
tracks = factories.TrackFactory.create_batch(size=100)
for i in range(20):
TrackFavorite.add(track=random.choice(tracks), user=self.user)
@ -73,7 +75,7 @@ class TestRadios(TestCase):
self.assertIn(pick, choices)
def test_can_use_radio_session_to_filter_choices(self):
tracks = mommy.make('music.Track', _quantity=30)
tracks = factories.TrackFactory.create_batch(size=30)
radio = radios.RandomRadio()
session = radio.start_session(self.user)
@ -85,7 +87,7 @@ class TestRadios(TestCase):
self.assertEqual(len(set(tracks_id)), 30)
def test_can_restore_radio_from_previous_session(self):
tracks = mommy.make('music.Track', _quantity=30)
tracks = factories.TrackFactory.create_batch(size=30)
radio = radios.RandomRadio()
session = radio.start_session(self.user)
@ -115,7 +117,7 @@ class TestRadios(TestCase):
self.assertIsNotNone(session.session_key)
def test_can_get_track_for_session_from_api(self):
tracks = mommy.make('music.Track', _quantity=1)
tracks = factories.TrackFactory.create_batch(size=1)
self.client.login(username=self.user.username, password='test')
url = reverse('api:v1:radios:sessions-list')
@ -129,7 +131,7 @@ class TestRadios(TestCase):
self.assertEqual(data['track']['id'], tracks[0].id)
self.assertEqual(data['position'], 1)
next_track = mommy.make('music.Track')
next_track = factories.TrackFactory()
response = self.client.post(url, {'session': session.pk})
data = json.loads(response.content.decode('utf-8'))
@ -148,9 +150,10 @@ class TestRadios(TestCase):
radio.start_session(self.user, related_object=self.user)
def test_can_start_artist_radio(self):
artist = mommy.make('music.Artist')
wrong_tracks = mommy.make('music.Track', _quantity=30)
good_tracks = mommy.make('music.Track', artist=artist, _quantity=5)
artist = factories.ArtistFactory()
wrong_tracks = factories.TrackFactory.create_batch(size=30)
good_tracks = factories.TrackFactory.create_batch(
artist=artist, size=5)
radio = radios.ArtistRadio()
session = radio.start_session(self.user, related_object=artist)
@ -159,9 +162,9 @@ class TestRadios(TestCase):
self.assertIn(radio.pick(), good_tracks)
def test_can_start_tag_radio(self):
tag = mommy.make('taggit.Tag')
wrong_tracks = mommy.make('music.Track', _quantity=30)
good_tracks = mommy.make('music.Track', _quantity=5)
tag = factories.TagFactory()
wrong_tracks = factories.TrackFactory.create_batch(size=30)
good_tracks = factories.TrackFactory.create_batch(size=5)
for track in good_tracks:
track.tags.add(tag)
@ -172,7 +175,7 @@ class TestRadios(TestCase):
self.assertIn(radio.pick(), good_tracks)
def test_can_start_artist_radio_from_api(self):
artist = mommy.make('music.Artist')
artist = factories.ArtistFactory()
url = reverse('api:v1:radios:sessions-list')
response = self.client.post(url, {'radio_type': 'artist', 'related_object_id': artist.id})
@ -181,10 +184,10 @@ class TestRadios(TestCase):
self.assertEqual(session.related_object, artist)
def test_can_start_less_listened_radio(self):
history = mommy.make('history.Listening', _quantity=5, user=self.user)
history = ListeningFactory.create_batch(size=5, user=self.user)
wrong_tracks = [h.track for h in history]
good_tracks = mommy.make('music.Track', _quantity=30)
good_tracks = factories.TrackFactory.create_batch(size=30)
radio = radios.LessListenedRadio()
session = radio.start_session(self.user)

Wyświetl plik

@ -6,4 +6,5 @@ router = routers.SimpleRouter()
router.register(r'sessions', views.RadioSessionViewSet, 'sessions')
router.register(r'tracks', views.RadioSessionTrackViewSet, 'tracks')
urlpatterns = router.urls

Wyświetl plik

@ -19,14 +19,14 @@ class RadioSessionViewSet(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 RadioSessionTrackViewSet(mixins.CreateModelMixin,
serializer.is_valid(raise_exception=True)
session = serializer.validated_data['session']
try:
if request.user.is_authenticated():
if request.user.is_authenticated:
assert request.user == session.user
else:
assert request.session.session_key == session.session_key

Wyświetl plik

@ -1,6 +1,11 @@
class AnonymousSessionMiddleware(object):
def process_request(self, request):
class AnonymousSessionMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
if not request.session.session_key:
request.session.save()
response = self.get_response(request)
return response

Wyświetl plik

@ -38,7 +38,7 @@ class Migration(migrations.Migration):
'verbose_name_plural': 'users',
},
managers=[
(b'objects', django.contrib.auth.models.UserManager()),
('objects', django.contrib.auth.models.UserManager()),
],
),
]

Wyświetl plik

@ -2,7 +2,7 @@
from __future__ import unicode_literals, absolute_import
from django.contrib.auth.models import AbstractUser
from django.core.urlresolvers import reverse
from django.urls import reverse
from django.db import models
from django.utils.encoding import python_2_unicode_compatible
from django.utils.translation import ugettext_lazy as _

Wyświetl plik

@ -1,59 +1,59 @@
# Bleeding edge Django
django==1.11
django>=2.0,<2.1
# Configuration
django-environ==0.4.0
django-secure==1.0.1
whitenoise==2.0.6
# Models
django-model-utils==2.3.1
django-environ>=0.4,<0.5
whitenoise>=3.3,<3.4
# Images
Pillow==3.0.0
Pillow>=4.3,<4.4
# For user registration, either via email or social
# Well-built with regular release cycles!
django-allauth==0.24.1
django-allauth>=0.34,<0.35
# Python-PostgreSQL Database Adapter
psycopg2==2.6.1
psycopg2>=2.7,<=2.8
# Time zones support
pytz==2015.7
pytz==2017.3
# Redis support
django-redis==4.3.0
redis>=2.10.0
django-redis>=4.5,<4.6
redis>=2.10,<2.11
celery==3.1.19
celery>=3.1,<3.2
# Your custom requirements go here
django-cors-headers==2.1.0
django-cors-headers>=2.1,<2.2
musicbrainzngs==0.6
youtube_dl>=2015.12.21
djangorestframework==3.6.3
djangorestframework-jwt==1.11.0
django-celery==3.2.1
django-mptt==0.8.7
google-api-python-client==1.6.2
arrow==0.10.0
django-taggit==0.22.1
persisting-theory==0.2.1
django-versatileimagefield==1.7.1
django-cachalot==1.5.0
django-filter==1.1
django-rest-auth==0.9.1
beautifulsoup4==4.6.0
Markdown==2.6.8
ipython==6.1.0
mutagen==1.38
youtube_dl>=2017.12.14
djangorestframework>=3.7,<3.8
djangorestframework-jwt>=1.11,<1.12
django-celery>=3.2,<3.3
django-mptt>=0.9,<0.10
google-api-python-client>=1.6,<1.7
arrow>=0.12,<0.13
persisting-theory>=0.2,<0.3
django-versatileimagefield>=1.8,<1.9
django-filter>=1.1,<1.2
django-rest-auth>=0.9,<0.10
beautifulsoup4>=4.6,<4.7
Markdown>=2.6,<2.7
ipython>=6,<7
mutagen>=1.39,<1.40
# Until this is merged
#django-taggit>=0.22,<0.23
git+https://github.com/jdufresne/django-taggit.git@e8f7f216f04c9781bebc84363ab24d575f948ede
# Until this is merged
git+https://github.com/EliotBerriot/PyMemoize.git@django
# Until this is merged
#django-cachalot==1.5.0
git+https://github.com/EliotBerriot/django-cachalot.git@django-2
django-dynamic-preferences>=1.3,<1.4
django-dynamic-preferences>=1.5,<1.6

Wyświetl plik

@ -1,15 +1,15 @@
# Local development dependencies go here
-r base.txt
coverage==4.0.3
django_coverage_plugin==1.1
Sphinx==1.6.2
django-extensions==1.5.9
Werkzeug==0.11.2
django-test-plus==1.0.11
coverage>=4.4,<4.5
django_coverage_plugin>=1.5,<1.6
Sphinx>=1.6,<1.7
django-extensions>=1.9,<1.10
Werkzeug>=0.13,<0.14
django-test-plus>=1.0.20
factory_boy>=2.8.1
# django-debug-toolbar that works with Django 1.5+
django-debug-toolbar>=1.5,<1.6
django-debug-toolbar>=1.9,<1.10
# improved REPL
ipdb==0.8.1

Wyświetl plik

@ -1,8 +1,5 @@
# Pro-tip: Try not to put anything here. There should be no dependency in
# production that isn't in development.
-r base.txt
# WSGI Handler
# ------------------------------------------------

Wyświetl plik

@ -1,9 +1,6 @@
# Test dependencies go here.
-r local.txt
flake8==2.5.0
model-mommy==1.3.2
flake8
pytest
pytest-django
pytest-mock

Wyświetl plik

@ -26,6 +26,7 @@ class Audio {
if (options.onEnded) {
this.onEnded = options.onEnded
}
this.onError = options.onError
this.state = {
preload: preload,
@ -60,8 +61,12 @@ class Audio {
init (src, options = {}) {
if (!src) throw Error('src must be required')
this.state.startLoad = true
if (this.state.tried === this.state.try) {
if (this.state.tried >= this.state.try) {
this.state.failed = true
logger.default.error('Cannot fetch audio', src)
if (this.onError) {
this.onError(src)
}
return
}
this.$Audio = new window.Audio(src)

Wyświetl plik

@ -140,7 +140,6 @@ class Queue {
} else {
index = index || this.tracks.length
}
console.log('INDEEEEEX', index)
tracks.forEach((t) => {
self.append(t, index, true)
index += 1
@ -243,7 +242,11 @@ class Queue {
rate: 1,
loop: false,
volume: this.state.volume,
onEnded: this.handleAudioEnded.bind(this)
onEnded: this.handleAudioEnded.bind(this),
onError: function (src) {
self.errored = true
self.next()
}
})
this.audio = audio
audio.updateHook('playState', function (e) {

Wyświetl plik

@ -0,0 +1,34 @@
<template>
<div class="main pusher">
<div class="ui vertical stripe segment">
<div class="ui text container">
<h1 class="ui huge header">
<i class="warning icon"></i>
<div class="content">
<strike>Whale</strike> Page not found!
</div>
</h1>
<p>We're sorry, the page you asked for does not exists.</p>
<p>Requested URL: <a :href="path">{{ path }}</a></p>
<router-link class="ui icon button" to="/">
Go to home page
<i class="right arrow icon"></i>
</router-link>
</div>
</div>
</div>
</template>
<script>
export default {
data: function () {
return {
path: window.location.href
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>

Wyświetl plik

@ -43,6 +43,9 @@ import auth from '@/auth'
export default {
name: 'login',
props: {
next: {type: String}
},
data () {
return {
// We need to initialize the component with any
@ -69,7 +72,7 @@ export default {
}
// We need to pass the component's this context
// to properly make use of http in the auth service
auth.login(this, credentials, {path: '/library'}, function (response) {
auth.login(this, credentials, {path: this.next}, function (response) {
// error callback
if (response.status === 400) {
self.error = 'invalid_credentials'

Wyświetl plik

@ -12,6 +12,10 @@
<label>{{ t }}</label>
</div>
</div>
<div class="field">
<label>Query template</label>
<input v-model="customQueryTemplate" />
</div>
</div>
</form>
<template
@ -22,6 +26,7 @@
:backends="backends"
:defaultEnabled="false"
:default-backend-id="defaultBackendId"
:query-template="customQueryTemplate"
@import-data-changed="recordReleaseData"
@enabled="recordReleaseEnabled"
></release-import>

Wyświetl plik

@ -13,10 +13,12 @@ export default {
metadata: {type: Object, required: true},
defaultEnabled: {type: Boolean, default: true},
backends: {type: Array},
defaultBackendId: {type: String}
defaultBackendId: {type: String},
queryTemplate: {type: String, default: '$artist $title'}
},
data () {
return {
customQueryTemplate: this.queryTemplate,
currentBackendId: this.defaultBackendId,
isImporting: false,
enabled: this.defaultEnabled
@ -56,6 +58,9 @@ export default {
return this.backends.filter(b => {
return b.id === self.currentBackendId
})[0]
},
realQueryTemplate () {
}
},
watch: {
@ -70,6 +75,14 @@ export default {
},
enabled (newValue) {
this.$emit('enabled', this.importData, newValue)
},
queryTemplate (newValue, oldValue) {
// we inherit from the prop template unless the component changed
// the value
if (oldValue === this.customQueryTemplate) {
// no changed from prop, we keep the sync
this.customQueryTemplate = newValue
}
}
}
}

Wyświetl plik

@ -20,6 +20,7 @@
:release-metadata="metadata"
:backends="backends"
:default-backend-id="defaultBackendId"
:query-template="customQueryTemplate"
@import-data-changed="recordTrackData"
@enabled="recordTrackEnabled"
></track-import>

Wyświetl plik

@ -92,13 +92,7 @@ export default Vue.extend({
releaseMetadata: {type: Object, required: true}
},
data () {
let queryParts = [
this.releaseMetadata['artist-credit'][0]['artist']['name'],
this.releaseMetadata['title'],
this.metadata['recording']['title']
]
return {
query: queryParts.join(' '),
isLoading: false,
results: [],
currentResultIndex: 0,
@ -151,6 +145,18 @@ export default Vue.extend({
mbid: this.metadata.recording.id,
source: this.importedUrl
}
},
query () {
let queryMapping = [
['artist', this.releaseMetadata['artist-credit'][0]['artist']['name']],
['album', this.releaseMetadata['title']],
['title', this.metadata['recording']['title']]
]
let query = this.customQueryTemplate
queryMapping.forEach(e => {
query = query.split('$' + e[0]).join(e[1])
})
return query
}
},
watch: {

Wyświetl plik

@ -32,7 +32,7 @@ Vue.http.interceptors.push(function (request, next) {
// redirect to login form when we get unauthorized response from server
if (response.status === 401) {
logger.default.warn('Received 401 response from API, redirecting to login form')
router.push({name: 'login'})
router.push({name: 'login', query: {next: router.currentRoute.fullPath}})
}
})
})

Wyświetl plik

@ -1,5 +1,6 @@
import Vue from 'vue'
import Router from 'vue-router'
import PageNotFound from '@/components/PageNotFound'
import Home from '@/components/Home'
import Login from '@/components/auth/Login'
import Profile from '@/components/auth/Profile'
@ -30,7 +31,8 @@ export default new Router({
{
path: '/login',
name: 'login',
component: Login
component: Login,
props: (route) => ({ next: route.query.next || '/library' })
},
{
path: '/logout',
@ -71,7 +73,7 @@ export default new Router({
},
{ path: 'import/batches/:id', name: 'library.import.batches.detail', component: BatchDetail, props: true }
]
}
},
{ path: '*', component: PageNotFound }
]
})