From 363acca53db4ea164e18892b603de4724bf05648 Mon Sep 17 00:00:00 2001
From: Eliot Berriot <contact@eliotberriot.com>
Date: Thu, 5 Apr 2018 23:26:41 +0200
Subject: [PATCH] AudioCollection to import job and track file creation

---
 .../migrations/0005_actor_followers.py        | 18 +++++++
 .../migrations/0023_auto_20180405_1830.py     | 47 +++++++++++++++++++
 api/funkwhale_api/music/models.py             | 47 ++++++++++++++++++-
 api/tests/music/test_import.py                |  4 ++
 4 files changed, 114 insertions(+), 2 deletions(-)
 create mode 100644 api/funkwhale_api/federation/migrations/0005_actor_followers.py
 create mode 100644 api/funkwhale_api/music/migrations/0023_auto_20180405_1830.py

diff --git a/api/funkwhale_api/federation/migrations/0005_actor_followers.py b/api/funkwhale_api/federation/migrations/0005_actor_followers.py
new file mode 100644
index 00000000..94a1c75a
--- /dev/null
+++ b/api/funkwhale_api/federation/migrations/0005_actor_followers.py
@@ -0,0 +1,18 @@
+# Generated by Django 2.0.3 on 2018-04-05 16:35
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('federation', '0004_followrequest'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='actor',
+            name='followers',
+            field=models.ManyToManyField(related_name='following', through='federation.Follow', to='federation.Actor'),
+        ),
+    ]
diff --git a/api/funkwhale_api/music/migrations/0023_auto_20180405_1830.py b/api/funkwhale_api/music/migrations/0023_auto_20180405_1830.py
new file mode 100644
index 00000000..3cef1f42
--- /dev/null
+++ b/api/funkwhale_api/music/migrations/0023_auto_20180405_1830.py
@@ -0,0 +1,47 @@
+# Generated by Django 2.0.3 on 2018-04-05 18:30
+
+from django.conf import settings
+import django.contrib.postgres.fields.jsonb
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('federation', '0005_actor_followers'),
+        ('music', '0022_importbatch_import_request'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='importbatch',
+            name='federation_actor',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='import_batches', to='federation.Actor'),
+        ),
+        migrations.AddField(
+            model_name='importbatch',
+            name='federation_source',
+            field=models.URLField(blank=True, null=True),
+        ),
+        migrations.AddField(
+            model_name='importjob',
+            name='federation_source',
+            field=models.URLField(blank=True, null=True),
+        ),
+        migrations.AddField(
+            model_name='importjob',
+            name='metadata',
+            field=django.contrib.postgres.fields.jsonb.JSONField(default={}),
+        ),
+        migrations.AlterField(
+            model_name='importbatch',
+            name='source',
+            field=models.CharField(choices=[('api', 'api'), ('shell', 'shell'), ('federation', 'federation')], default='api', max_length=30),
+        ),
+        migrations.AlterField(
+            model_name='importbatch',
+            name='submitted_by',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='imports', to=settings.AUTH_USER_MODEL),
+        ),
+    ]
diff --git a/api/funkwhale_api/music/models.py b/api/funkwhale_api/music/models.py
index 7138dcdd..cff16297 100644
--- a/api/funkwhale_api/music/models.py
+++ b/api/funkwhale_api/music/models.py
@@ -8,6 +8,7 @@ import markdown
 
 from django.conf import settings
 from django.db import models
+from django.contrib.postgres.fields import JSONField
 from django.core.files.base import ContentFile
 from django.core.files import File
 from django.db.models.signals import post_save
@@ -65,6 +66,7 @@ class APIModelMixin(models.Model):
                 pass
         return cleaned_data
 
+
 class Artist(APIModelMixin):
     name = models.CharField(max_length=255)
 
@@ -90,10 +92,19 @@ class Artist(APIModelMixin):
                 t.append(tag)
         return set(t)
 
+    @classmethod
+    def get_or_create_from_name(cls, name, **kwargs):
+        kwargs.update({'name': name})
+        return cls.objects.get_or_create(
+            name__iexact=name,
+            defaults=kwargs)[0]
+
+
 def import_artist(v):
     a = Artist.get_or_create_from_api(mbid=v[0]['artist']['id'])[0]
     return a
 
+
 def parse_date(v):
     if len(v) == 4:
         return datetime.date(int(v), 1, 1)
@@ -108,6 +119,7 @@ def import_tracks(instance, cleaned_data, raw_data):
         track_cleaned_data['position'] = int(track_data['position'])
         track = importers.load(Track, track_cleaned_data, track_data, Track.import_hooks)
 
+
 class Album(APIModelMixin):
     title = models.CharField(max_length=255)
     artist = models.ForeignKey(
@@ -170,6 +182,14 @@ class Album(APIModelMixin):
                 t.append(tag)
         return set(t)
 
+    @classmethod
+    def get_or_create_from_title(cls, title, **kwargs):
+        kwargs.update({'title': title})
+        return cls.objects.get_or_create(
+            title__iexact=title,
+            defaults=kwargs)[0]
+
+
 def import_tags(instance, cleaned_data, raw_data):
     MINIMUM_COUNT = 2
     tags_to_add = []
@@ -182,6 +202,7 @@ def import_tags(instance, cleaned_data, raw_data):
         tags_to_add.append(tag_data['name'])
     instance.tags.add(*tags_to_add)
 
+
 def import_album(v):
     a = Album.get_or_create_from_api(mbid=v[0]['id'])[0]
     return a
@@ -328,7 +349,7 @@ class Track(APIModelMixin):
     def save(self, **kwargs):
         try:
             self.artist
-        except  Artist.DoesNotExist:
+        except Artist.DoesNotExist:
             self.artist = self.album.artist
         super().save(**kwargs)
 
@@ -366,6 +387,13 @@ class Track(APIModelMixin):
                 self.mbid)
         return settings.FUNKWHALE_URL + '/tracks/{}'.format(self.pk)
 
+    @classmethod
+    def get_or_create_from_title(cls, title, **kwargs):
+        kwargs.update({'title': title})
+        return cls.objects.get_or_create(
+            title__iexact=title,
+            defaults=kwargs)[0]
+
 
 class TrackFile(models.Model):
     track = models.ForeignKey(
@@ -420,7 +448,8 @@ IMPORT_STATUS_CHOICES = (
 class ImportBatch(models.Model):
     IMPORT_BATCH_SOURCES = [
         ('api', 'api'),
-        ('shell', 'shell')
+        ('shell', 'shell'),
+        ('federation', 'federation'),
     ]
     source = models.CharField(
         max_length=30, default='api', choices=IMPORT_BATCH_SOURCES)
@@ -428,6 +457,8 @@ class ImportBatch(models.Model):
     submitted_by = models.ForeignKey(
         'users.User',
         related_name='imports',
+        null=True,
+        blank=True,
         on_delete=models.CASCADE)
     status = models.CharField(
         choices=IMPORT_STATUS_CHOICES, default='pending', max_length=30)
@@ -437,6 +468,16 @@ class ImportBatch(models.Model):
         null=True,
         blank=True,
         on_delete=models.CASCADE)
+
+    federation_source = models.URLField(null=True, blank=True)
+    federation_actor = models.ForeignKey(
+        'federation.Actor',
+        on_delete=models.SET_NULL,
+        null=True,
+        blank=True,
+        related_name='import_batches',
+    )
+
     class Meta:
         ordering = ['-creation_date']
 
@@ -464,6 +505,8 @@ class ImportJob(models.Model):
         choices=IMPORT_STATUS_CHOICES, default='pending', max_length=30)
     audio_file = models.FileField(
         upload_to='imports/%Y/%m/%d', max_length=255, null=True, blank=True)
+    federation_source = models.URLField(null=True, blank=True)
+    metadata = JSONField(default={})
 
     class Meta:
         ordering = ('id', )
diff --git a/api/tests/music/test_import.py b/api/tests/music/test_import.py
index e9ad9d0f..87e1899d 100644
--- a/api/tests/music/test_import.py
+++ b/api/tests/music/test_import.py
@@ -61,6 +61,7 @@ def test_import_job_from_federation_no_musicbrainz(factories):
     job.refresh_from_db()
 
     tf = job.track_file
+    assert tf.source == job.source
     assert tf.track.title == 'Ping'
     assert tf.track.artist.name == 'Hello'
     assert tf.track.album.title == 'World'
@@ -82,6 +83,7 @@ def test_import_job_from_federation_musicbrainz_recording(factories, mocker):
     job.refresh_from_db()
 
     tf = job.track_file
+    assert tf.source == job.source
     assert tf.track == t
     track_from_api.assert_called_once_with(
         mbid=tasks.get_mbid(job.metadata['recording'], 'recording'))
@@ -103,6 +105,7 @@ def test_import_job_from_federation_musicbrainz_release(factories, mocker):
     job.refresh_from_db()
 
     tf = job.track_file
+    assert tf.source == job.source
     assert tf.track.title == 'Ping'
     assert tf.track.artist == a.artist
     assert tf.track.album == a
@@ -127,6 +130,7 @@ def test_import_job_from_federation_musicbrainz_artist(factories, mocker):
     job.refresh_from_db()
 
     tf = job.track_file
+    assert tf.source == job.source
     assert tf.track.title == 'Ping'
     assert tf.track.artist == a
     assert tf.track.album.artist == a
-- 
GitLab