From e90e9dc7aaa98867b60c12ff7c3843f428586e5e Mon Sep 17 00:00:00 2001 From: Eliot Berriot <contact@eliotberriot.com> Date: Thu, 14 Dec 2017 23:06:21 +0100 Subject: [PATCH] Fixed #44: now bind track file to import job --- CHANGELOG | 1 + api/config/settings/common.py | 1 + .../migrations/0003_auto_20171214_2205.py | 27 +++++++++++++++ api/funkwhale_api/music/admin.py | 7 +++- .../migrations/0014_importjob_track_file.py | 21 ++++++++++++ .../0015_bind_track_file_to_import_job.py | 34 +++++++++++++++++++ api/funkwhale_api/music/models.py | 6 +++- api/funkwhale_api/music/serializers.py | 34 ++++++++++++------- api/funkwhale_api/music/tests/factories.py | 17 ++++++++++ api/funkwhale_api/music/tests/test_models.py | 10 ++++++ api/funkwhale_api/music/views.py | 5 ++- .../migrations/0002_auto_20171214_2205.py | 28 +++++++++++++++ api/requirements/test.txt | 2 +- .../components/library/import/BatchDetail.vue | 4 +++ 14 files changed, 181 insertions(+), 16 deletions(-) create mode 100644 api/funkwhale_api/contrib/sites/migrations/0003_auto_20171214_2205.py create mode 100644 api/funkwhale_api/music/migrations/0014_importjob_track_file.py create mode 100644 api/funkwhale_api/music/migrations/0015_bind_track_file_to_import_job.py create mode 100644 api/funkwhale_api/users/migrations/0002_auto_20171214_2205.py diff --git a/CHANGELOG b/CHANGELOG index 5ab83783..444d6f19 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -8,6 +8,7 @@ Changelog Features: - Models: now store relese group mbid on Album model (#7) +- Models: now bind import job to track files (#44) Bugfixes: diff --git a/api/config/settings/common.py b/api/config/settings/common.py index 0fa7bbe5..b10a0310 100644 --- a/api/config/settings/common.py +++ b/api/config/settings/common.py @@ -336,3 +336,4 @@ CACHALOT_ENABLED = env.bool('CACHALOT_ENABLED', default=True) # Custom Admin URL, use {% url 'admin:index' %} ADMIN_URL = env('DJANGO_ADMIN_URL', default='^api/admin/') +CSRF_USE_SESSIONS = True diff --git a/api/funkwhale_api/contrib/sites/migrations/0003_auto_20171214_2205.py b/api/funkwhale_api/contrib/sites/migrations/0003_auto_20171214_2205.py new file mode 100644 index 00000000..14a9ec1a --- /dev/null +++ b/api/funkwhale_api/contrib/sites/migrations/0003_auto_20171214_2205.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11 on 2017-12-14 22:05 +from __future__ import unicode_literals + +import django.contrib.sites.models +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('sites', '0002_set_site_domain_and_name'), + ] + + operations = [ + migrations.AlterModelManagers( + name='site', + managers=[ + ('objects', django.contrib.sites.models.SiteManager()), + ], + ), + migrations.AlterField( + model_name='site', + name='domain', + field=models.CharField(max_length=100, unique=True, validators=[django.contrib.sites.models._simple_domain_name_validator], verbose_name='domain name'), + ), + ] diff --git a/api/funkwhale_api/music/admin.py b/api/funkwhale_api/music/admin.py index a6a7f94f..524b8538 100644 --- a/api/funkwhale_api/music/admin.py +++ b/api/funkwhale_api/music/admin.py @@ -2,30 +2,35 @@ from django.contrib import admin from . import models + @admin.register(models.Artist) class ArtistAdmin(admin.ModelAdmin): list_display = ['name', 'mbid', 'creation_date'] search_fields = ['name', 'mbid'] + @admin.register(models.Album) class AlbumAdmin(admin.ModelAdmin): list_display = ['title', 'artist', 'mbid', 'release_date', 'creation_date'] search_fields = ['title', 'artist__name', 'mbid'] list_select_related = True + @admin.register(models.Track) class TrackAdmin(admin.ModelAdmin): list_display = ['title', 'artist', 'album', 'mbid'] search_fields = ['title', 'artist__name', 'album__title', 'mbid'] list_select_related = True + @admin.register(models.ImportBatch) class ImportBatchAdmin(admin.ModelAdmin): list_display = ['creation_date', 'status'] + @admin.register(models.ImportJob) class ImportJobAdmin(admin.ModelAdmin): - list_display = ['source', 'batch', 'status', 'mbid'] + list_display = ['source', 'batch', 'track_file', 'status', 'mbid'] list_select_related = True search_fields = ['source', 'batch__pk', 'mbid'] list_filter = ['status'] diff --git a/api/funkwhale_api/music/migrations/0014_importjob_track_file.py b/api/funkwhale_api/music/migrations/0014_importjob_track_file.py new file mode 100644 index 00000000..6950fd3c --- /dev/null +++ b/api/funkwhale_api/music/migrations/0014_importjob_track_file.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11 on 2017-12-14 21:14 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('music', '0013_auto_20171213_2211'), + ] + + operations = [ + migrations.AddField( + model_name='importjob', + name='track_file', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='jobs', to='music.TrackFile'), + ), + ] diff --git a/api/funkwhale_api/music/migrations/0015_bind_track_file_to_import_job.py b/api/funkwhale_api/music/migrations/0015_bind_track_file_to_import_job.py new file mode 100644 index 00000000..edb5e647 --- /dev/null +++ b/api/funkwhale_api/music/migrations/0015_bind_track_file_to_import_job.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals +import os + +from django.db import migrations, models +from funkwhale_api.common.utils import rename_file + + +def bind_jobs(apps, schema_editor): + TrackFile = apps.get_model("music", "TrackFile") + ImportJob = apps.get_model("music", "ImportJob") + + for job in ImportJob.objects.all().only('mbid'): + f = TrackFile.objects.filter(track__mbid=job.mbid).first() + if not f: + print('No file for mbid {}'.format(job.mbid)) + continue + job.track_file = f + job.save(update_fields=['track_file']) + + +def rewind(apps, schema_editor): + pass + + +class Migration(migrations.Migration): + + dependencies = [ + ('music', '0014_importjob_track_file'), + ] + + operations = [ + migrations.RunPython(bind_jobs, rewind), + ] diff --git a/api/funkwhale_api/music/models.py b/api/funkwhale_api/music/models.py index d87da1eb..95a47fd4 100644 --- a/api/funkwhale_api/music/models.py +++ b/api/funkwhale_api/music/models.py @@ -393,6 +393,8 @@ class ImportBatch(models.Model): class ImportJob(models.Model): batch = models.ForeignKey(ImportBatch, related_name='jobs') + track_file = models.ForeignKey( + TrackFile, related_name='jobs', null=True, blank=True) source = models.URLField() mbid = models.UUIDField(editable=False) STATUS_CHOICES = ( @@ -413,10 +415,12 @@ class ImportJob(models.Model): elif track.files.count() > 0: return - track_file = track_file or TrackFile(track=track, source=self.source) + track_file = track_file or TrackFile( + track=track, source=self.source) track_file.download_file() track_file.save() self.status = 'finished' + self.track_file = track_file self.save() return track.pk diff --git a/api/funkwhale_api/music/serializers.py b/api/funkwhale_api/music/serializers.py index 744115f8..43daf9d5 100644 --- a/api/funkwhale_api/music/serializers.py +++ b/api/funkwhale_api/music/serializers.py @@ -9,35 +9,26 @@ class TagSerializer(serializers.ModelSerializer): model = Tag fields = ('id', 'name', 'slug') + class SimpleArtistSerializer(serializers.ModelSerializer): class Meta: model = models.Artist fields = ('id', 'mbid', 'name') + class ArtistSerializer(serializers.ModelSerializer): tags = TagSerializer(many=True, read_only=True) class Meta: model = models.Artist fields = ('id', 'mbid', 'name', 'tags') -class ImportJobSerializer(serializers.ModelSerializer): - class Meta: - model = models.ImportJob - fields = ('id', 'mbid', 'source', 'status') - -class ImportBatchSerializer(serializers.ModelSerializer): - jobs = ImportJobSerializer(many=True, read_only=True) - class Meta: - model = models.ImportBatch - fields = ('id', 'jobs', 'status', 'creation_date') - class TrackFileSerializer(serializers.ModelSerializer): path = serializers.SerializerMethodField() class Meta: model = models.TrackFile - fields = ('id', 'path', 'duration', 'source', 'filename') + fields = ('id', 'path', 'duration', 'source', 'filename', 'track') def get_path(self, o): request = self.context.get('request') @@ -46,12 +37,14 @@ class TrackFileSerializer(serializers.ModelSerializer): url = request.build_absolute_uri(url) return url + class SimpleAlbumSerializer(serializers.ModelSerializer): class Meta: model = models.Album fields = ('id', 'mbid', 'title', 'release_date', 'cover') + class AlbumSerializer(serializers.ModelSerializer): tags = TagSerializer(many=True, read_only=True) class Meta: @@ -81,6 +74,7 @@ class TrackSerializer(LyricsMixin): 'position', 'lyrics') + class TrackSerializerNested(LyricsMixin): artist = ArtistSerializer() files = TrackFileSerializer(many=True, read_only=True) @@ -90,6 +84,7 @@ class TrackSerializerNested(LyricsMixin): model = models.Track fields = ('id', 'mbid', 'title', 'artist', 'files', 'album', 'tags', 'lyrics') + class AlbumSerializerNested(serializers.ModelSerializer): tracks = TrackSerializer(many=True, read_only=True) artist = SimpleArtistSerializer() @@ -99,6 +94,7 @@ class AlbumSerializerNested(serializers.ModelSerializer): model = models.Album fields = ('id', 'mbid', 'title', 'cover', 'artist', 'release_date', 'tracks', 'tags') + class ArtistSerializerNested(serializers.ModelSerializer): albums = AlbumSerializerNested(many=True, read_only=True) tags = TagSerializer(many=True, read_only=True) @@ -111,3 +107,17 @@ class LyricsSerializer(serializers.ModelSerializer): class Meta: model = models.Lyrics fields = ('id', 'work', 'content', 'content_rendered') + + +class ImportJobSerializer(serializers.ModelSerializer): + track_file = TrackFileSerializer(read_only=True) + class Meta: + model = models.ImportJob + fields = ('id', 'mbid', 'source', 'status', 'track_file') + + +class ImportBatchSerializer(serializers.ModelSerializer): + jobs = ImportJobSerializer(many=True, read_only=True) + class Meta: + model = models.ImportBatch + fields = ('id', 'jobs', 'status', 'creation_date') diff --git a/api/funkwhale_api/music/tests/factories.py b/api/funkwhale_api/music/tests/factories.py index d3cd625b..b554e3e1 100644 --- a/api/funkwhale_api/music/tests/factories.py +++ b/api/funkwhale_api/music/tests/factories.py @@ -1,6 +1,8 @@ import factory import os +from funkwhale_api.users.tests.factories import UserFactory + SAMPLES_PATH = os.path.dirname(os.path.abspath(__file__)) @@ -42,3 +44,18 @@ class TrackFileFactory(factory.django.DjangoModelFactory): class Meta: model = 'music.TrackFile' + + +class ImportBatchFactory(factory.django.DjangoModelFactory): + submitted_by = factory.SubFactory(UserFactory) + + class Meta: + model = 'music.ImportBatch' + + +class ImportJobFactory(factory.django.DjangoModelFactory): + batch = factory.SubFactory(ImportBatchFactory) + source = factory.Faker('url') + + class Meta: + model = 'music.ImportJob' diff --git a/api/funkwhale_api/music/tests/test_models.py b/api/funkwhale_api/music/tests/test_models.py index a652676d..4b43e463 100644 --- a/api/funkwhale_api/music/tests/test_models.py +++ b/api/funkwhale_api/music/tests/test_models.py @@ -39,3 +39,13 @@ def test_import_album_stores_release_group(db): assert album.release_group_id == album_data['release-group']['id'] assert album.artist == artist + + +def test_import_job_is_bound_to_track_file(db, mocker): + track = factories.TrackFactory() + job = factories.ImportJobFactory(mbid=track.mbid) + + mocker.patch('funkwhale_api.music.models.TrackFile.download_file') + job.run() + job.refresh_from_db() + assert job.track_file.track == track diff --git a/api/funkwhale_api/music/views.py b/api/funkwhale_api/music/views.py index d149b5d1..72982e4c 100644 --- a/api/funkwhale_api/music/views.py +++ b/api/funkwhale_api/music/views.py @@ -72,7 +72,10 @@ class AlbumViewSet(SearchMixin, viewsets.ReadOnlyModelViewSet): class ImportBatchViewSet(viewsets.ReadOnlyModelViewSet): - queryset = models.ImportBatch.objects.all().order_by('-creation_date') + queryset = ( + models.ImportBatch.objects.all() + .prefetch_related('jobs__track_file') + .order_by('-creation_date')) serializer_class = serializers.ImportBatchSerializer def get_queryset(self): diff --git a/api/funkwhale_api/users/migrations/0002_auto_20171214_2205.py b/api/funkwhale_api/users/migrations/0002_auto_20171214_2205.py new file mode 100644 index 00000000..4bbbaa62 --- /dev/null +++ b/api/funkwhale_api/users/migrations/0002_auto_20171214_2205.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11 on 2017-12-14 22:05 +from __future__ import unicode_literals + +import django.contrib.auth.models +import django.contrib.auth.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('users', '0001_initial'), + ] + + operations = [ + migrations.AlterModelManagers( + name='user', + managers=[ + ('objects', django.contrib.auth.models.UserManager()), + ], + ), + migrations.AlterField( + model_name='user', + name='username', + field=models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username'), + ), + ] diff --git a/api/requirements/test.txt b/api/requirements/test.txt index a26cf5bd..7c304bbd 100644 --- a/api/requirements/test.txt +++ b/api/requirements/test.txt @@ -4,8 +4,8 @@ flake8==2.5.0 model-mommy==1.3.2 -tox==2.7.0 pytest pytest-django +pytest-mock pytest-sugar pytest-xdist diff --git a/front/src/components/library/import/BatchDetail.vue b/front/src/components/library/import/BatchDetail.vue index 57560fc0..726ec9c3 100644 --- a/front/src/components/library/import/BatchDetail.vue +++ b/front/src/components/library/import/BatchDetail.vue @@ -23,6 +23,7 @@ <th>Recording MusicBrainz ID</th> <th>Source</th> <th>Status</th> + <th>Track</th> </tr> </thead> <tbody> @@ -38,6 +39,9 @@ <span :class="['ui', {'yellow': job.status === 'pending'}, {'green': job.status === 'finished'}, 'label']">{{ job.status }}</span> </td> + <td> + <router-link v-if="job.track_file" :to="{name: 'library.tracks.detail', params: {id: job.track_file.track }}">{{ job.track_file.track }}</router-link> + </td> </tr> </tbody> </table> -- GitLab