Added status field to import batch, it's synced based on jobs

This commit is contained in:
Eliot Berriot 2018-02-21 00:02:09 +01:00
parent 15bdf18705
commit 24e2555793
No known key found for this signature in database
GPG Key ID: DD6965E2476E5C27
5 changed files with 97 additions and 17 deletions

View File

@ -0,0 +1,18 @@
# Generated by Django 2.0.2 on 2018-02-20 19:12
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('music', '0019_populate_mimetypes'),
]
operations = [
migrations.AddField(
model_name='importbatch',
name='status',
field=models.CharField(choices=[('pending', 'Pending'), ('finished', 'Finished'), ('errored', 'Errored'), ('skipped', 'Skipped')], default='pending', max_length=30),
),
]

View File

@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import os
from django.db import migrations, models
def populate_status(apps, schema_editor):
from funkwhale_api.music.utils import compute_status
ImportBatch = apps.get_model("music", "ImportBatch")
for ib in ImportBatch.objects.prefetch_related('jobs'):
ib.status = compute_status(ib.jobs.all())
ib.save(update_fields=['status'])
def rewind(apps, schema_editor):
pass
class Migration(migrations.Migration):
dependencies = [
('music', '0020_importbatch_status'),
]
operations = [
migrations.RunPython(populate_status, rewind),
]

View File

@ -10,8 +10,11 @@ from django.conf import settings
from django.db import models from django.db import models
from django.core.files.base import ContentFile from django.core.files.base import ContentFile
from django.core.files import File from django.core.files import File
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.urls import reverse from django.urls import reverse
from django.utils import timezone from django.utils import timezone
from taggit.managers import TaggableManager from taggit.managers import TaggableManager
from versatileimagefield.fields import VersatileImageField from versatileimagefield.fields import VersatileImageField
@ -400,6 +403,14 @@ class TrackFile(models.Model):
self.mimetype = utils.guess_mimetype(self.audio_file) self.mimetype = utils.guess_mimetype(self.audio_file)
return super().save(**kwargs) return super().save(**kwargs)
IMPORT_STATUS_CHOICES = (
('pending', 'Pending'),
('finished', 'Finished'),
('errored', 'Errored'),
('skipped', 'Skipped'),
)
class ImportBatch(models.Model): class ImportBatch(models.Model):
IMPORT_BATCH_SOURCES = [ IMPORT_BATCH_SOURCES = [
('api', 'api'), ('api', 'api'),
@ -412,22 +423,24 @@ class ImportBatch(models.Model):
'users.User', 'users.User',
related_name='imports', related_name='imports',
on_delete=models.CASCADE) on_delete=models.CASCADE)
status = models.CharField(
choices=IMPORT_STATUS_CHOICES, default='pending', max_length=30)
import_request = models.ForeignKey(
'requests.ImportRequest',
related_name='import_batches',
null=True,
blank=True,
on_delete=models.CASCADE)
class Meta: class Meta:
ordering = ['-creation_date'] ordering = ['-creation_date']
def __str__(self): def __str__(self):
return str(self.pk) return str(self.pk)
@property def update_status(self):
def status(self): self.status = utils.compute_status(self.jobs.all())
pending = any([job.status == 'pending' for job in self.jobs.all()]) self.save(update_fields=['status'])
errored = any([job.status == 'errored' for job in self.jobs.all()])
if pending:
return 'pending'
if errored:
return 'errored'
return 'finished'
class ImportJob(models.Model): class ImportJob(models.Model):
batch = models.ForeignKey( batch = models.ForeignKey(
@ -440,13 +453,9 @@ class ImportJob(models.Model):
on_delete=models.CASCADE) on_delete=models.CASCADE)
source = models.CharField(max_length=500) source = models.CharField(max_length=500)
mbid = models.UUIDField(editable=False, null=True, blank=True) mbid = models.UUIDField(editable=False, null=True, blank=True)
STATUS_CHOICES = (
('pending', 'Pending'), status = models.CharField(
('finished', 'Finished'), choices=IMPORT_STATUS_CHOICES, default='pending', max_length=30)
('errored', 'Errored'),
('skipped', 'Skipped'),
)
status = models.CharField(choices=STATUS_CHOICES, default='pending', max_length=30)
audio_file = models.FileField( audio_file = models.FileField(
upload_to='imports/%Y/%m/%d', max_length=255, null=True, blank=True) upload_to='imports/%Y/%m/%d', max_length=255, null=True, blank=True)

View File

@ -43,3 +43,13 @@ def get_query(query_string, search_fields):
def guess_mimetype(f): def guess_mimetype(f):
b = min(100000, f.size) b = min(100000, f.size)
return magic.from_buffer(f.read(b), mime=True) return magic.from_buffer(f.read(b), mime=True)
def compute_status(jobs):
errored = any([job.status == 'errored' for job in jobs])
if errored:
return 'errored'
pending = any([job.status == 'pending' for job in jobs])
if pending:
return 'pending'
return 'finished'

View File

@ -52,6 +52,20 @@ def test_import_job_is_bound_to_track_file(factories, mocker):
job.refresh_from_db() job.refresh_from_db()
assert job.track_file.track == track assert job.track_file.track == track
@pytest.mark.parametrize('status', ['pending', 'errored', 'finished'])
def test_saving_job_updates_batch_status(status,factories, mocker):
batch = factories['music.ImportBatch']()
assert batch.status == 'pending'
job = factories['music.ImportJob'](batch=batch, status=status)
batch.refresh_from_db()
assert batch.status == status
@pytest.mark.parametrize('extention,mimetype', [ @pytest.mark.parametrize('extention,mimetype', [
('ogg', 'audio/ogg'), ('ogg', 'audio/ogg'),
('mp3', 'audio/mpeg'), ('mp3', 'audio/mpeg'),