Verified Commit 78d0de0e authored by Eliot Berriot's avatar Eliot Berriot
Browse files

Merge branch 'release/0.8'

parents 3673f624 1a5b7ed2
......@@ -4,7 +4,7 @@ from . import models
@admin.register(models.Listening)
class ListeningAdmin(admin.ModelAdmin):
list_display = ['track', 'end_date', 'user', 'session_key']
list_display = ['track', 'creation_date', 'user', 'session_key']
search_fields = ['track__name', 'user__username']
list_select_related = [
'user',
......
# Generated by Django 2.0.3 on 2018-03-25 14:33
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('history', '0001_initial'),
]
operations = [
migrations.AlterModelOptions(
name='listening',
options={'ordering': ('-creation_date',)},
),
migrations.RenameField(
model_name='listening',
old_name='end_date',
new_name='creation_date',
),
]
......@@ -6,7 +6,8 @@ from funkwhale_api.music.models import Track
class Listening(models.Model):
end_date = models.DateTimeField(default=timezone.now, null=True, blank=True)
creation_date = models.DateTimeField(
default=timezone.now, null=True, blank=True)
track = models.ForeignKey(
Track, related_name="listenings", on_delete=models.CASCADE)
user = models.ForeignKey(
......@@ -18,7 +19,7 @@ class Listening(models.Model):
session_key = models.CharField(max_length=100, null=True, blank=True)
class Meta:
ordering = ('-end_date',)
ordering = ('-creation_date',)
def save(self, **kwargs):
if not self.user and not self.session_key:
......
......@@ -12,7 +12,7 @@ class ListeningActivitySerializer(activity_serializers.ModelSerializer):
type = serializers.SerializerMethodField()
object = TrackActivitySerializer(source='track')
actor = UserActivitySerializer(source='user')
published = serializers.DateTimeField(source='end_date')
published = serializers.DateTimeField(source='creation_date')
class Meta:
model = models.Listening
......@@ -36,7 +36,7 @@ class ListeningSerializer(serializers.ModelSerializer):
class Meta:
model = models.Listening
fields = ('id', 'user', 'session_key', 'track', 'end_date')
fields = ('id', 'user', 'session_key', 'track', 'creation_date')
def create(self, validated_data):
......
......@@ -121,7 +121,13 @@ class Metadata(object):
def __init__(self, path):
self._file = mutagen.File(path)
self._conf = CONF[self.get_file_type(self._file)]
if self._file is None:
raise ValueError('Cannot parse metadata from {}'.format(path))
ft = self.get_file_type(self._file)
try:
self._conf = CONF[ft]
except KeyError:
raise ValueError('Unsupported format {}'.format(ft))
def get_file_type(self, f):
return f.__class__.__name__
......
......@@ -328,7 +328,7 @@ class SubmitViewSet(viewsets.ViewSet):
job = models.ImportJob.objects.create(mbid=request.POST['mbid'], batch=batch, source=request.POST['import_url'])
tasks.import_job_run.delay(import_job_id=job.pk)
serializer = serializers.ImportBatchSerializer(batch)
return Response(serializer.data)
return Response(serializer.data, status=201)
def get_import_request(self, data):
try:
......
......@@ -34,6 +34,13 @@ class Command(BaseCommand):
default=False,
help='Will launch celery tasks for each file to import instead of doing it synchronously and block the CLI',
)
parser.add_argument(
'--exit', '-x',
action='store_true',
dest='exit_on_failure',
default=False,
help='use this flag to disable error catching',
)
parser.add_argument(
'--no-acoustid',
action='store_true',
......@@ -106,20 +113,27 @@ class Command(BaseCommand):
async = options['async']
import_handler = tasks.import_job_run.delay if async else tasks.import_job_run
for path in matching:
job = batch.jobs.create(
source='file://' + path,
)
name = os.path.basename(path)
with open(path, 'rb') as f:
job.audio_file.save(name, File(f))
job.save()
try:
utils.on_commit(
import_handler,
import_job_id=job.pk,
use_acoustid=not options['no_acoustid'])
self.stdout.write(message.format(path))
self.import_file(path, batch, import_handler, options)
except Exception as e:
self.stdout.write('Error: {}'.format(e))
if options['exit_on_failure']:
raise
m = 'Error while importing {}: {} {}'.format(
path, e.__class__.__name__, e)
self.stderr.write(m)
return batch
def import_file(self, path, batch, import_handler, options):
job = batch.jobs.create(
source='file://' + path,
)
name = os.path.basename(path)
with open(path, 'rb') as f:
job.audio_file.save(name, File(f))
job.save()
utils.on_commit(
import_handler,
import_job_id=job.pk,
use_acoustid=not options['no_acoustid'])
from rest_framework import serializers
from funkwhale_api.music.serializers import TrackSerializerNested
from funkwhale_api.users.serializers import UserBasicSerializer
from . import filters
from . import models
......@@ -15,6 +16,8 @@ class FilterSerializer(serializers.Serializer):
class RadioSerializer(serializers.ModelSerializer):
user = UserBasicSerializer(read_only=True)
class Meta:
model = models.Radio
fields = (
......
......@@ -20,6 +20,7 @@ class RadioViewSet(
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.ListModelMixin,
mixins.DestroyModelMixin,
viewsets.GenericViewSet):
serializer_class = serializers.RadioSerializer
......@@ -40,6 +41,16 @@ class RadioViewSet(
raise Http404
return serializer.save(user=self.request.user)
@detail_route(methods=['get'])
def tracks(self, request, *args, **kwargs):
radio = self.get_object()
tracks = radio.get_candidates().for_nested_serialization()
page = self.paginate_queryset(tracks)
if page is not None:
serializer = TrackSerializerNested(page, many=True)
return self.get_paginated_response(serializer.data)
@list_route(methods=['get'])
def filters(self, request, *args, **kwargs):
serializer = serializers.FilterSerializer(
......
#!/usr/bin/env python
import django
import os
import sys
......@@ -7,6 +8,12 @@ sys.path.append(os.path.dirname(os.path.abspath(__file__)))
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.production")
# we're doing this here since otherwise, missing environment
# files in settings result in AttributeError being raised, generating
# a cryptic django.core.exceptions.AppRegistryNotReady error.
# To prevent that, we explicitely load settings here before anything
# else, so we fail fast with a relevant error. See #140 for more details.
django.setup()
from django.core.management import execute_from_command_line
......
# This file is here because many Platforms as a Service look for
# requirements.txt in the root directory of a project.
-r requirements/base.txt
-r requirements/production.txt
......@@ -14,7 +14,7 @@ django-allauth>=0.34,<0.35
# Python-PostgreSQL Database Adapter
psycopg2>=2.7,<=2.8
psycopg2-binary>=2.7,<=2.8
# Time zones support
pytz==2017.3
......@@ -60,3 +60,7 @@ channels_redis>=2.1,<2.2
django-cacheops>=4,<4.1
daphne==2.0.4
cryptography>=2,<3
# requests-http-signature==0.0.3
# clone until the branch is merged and released upstream
git+https://github.com/EliotBerriot/requests-http-signature.git@signature-header-support
......@@ -9,3 +9,6 @@ git+https://github.com/pytest-dev/pytest-django.git@d3d9bb3ef6f0377cb5356eb36899
pytest-mock
pytest-sugar
pytest-xdist
pytest-cov
pytest-env
requests-mock
......@@ -7,6 +7,12 @@ max-line-length = 120
exclude=.tox,.git,*/migrations/*,*/static/CACHE/*,docs,node_modules
[tool:pytest]
DJANGO_SETTINGS_MODULE=config.settings.test
python_files = tests.py test_*.py *_tests.py
testpaths = tests
env =
SECRET_KEY=test
DJANGO_EMAIL_BACKEND=django.core.mail.backends.console.EmailBackend
CELERY_BROKER_URL=memory://
CELERY_TASK_ALWAYS_EAGER=True
CACHEOPS_ENABLED=False
FEDERATION_HOSTNAME=test.federation
from funkwhale_api.activity import serializers
from funkwhale_api.favorites.serializers import TrackFavoriteActivitySerializer
from funkwhale_api.history.serializers import \
ListeningActivitySerializer
def test_autoserializer(factories):
favorite = factories['favorites.TrackFavorite']()
listening = factories['history.Listening']()
objects = [favorite, listening]
serializer = serializers.AutoSerializer(objects, many=True)
expected = [
TrackFavoriteActivitySerializer(favorite).data,
ListeningActivitySerializer(listening).data,
]
assert serializer.data == expected
from funkwhale_api.activity import utils
def test_get_activity(factories):
user = factories['users.User']()
listening = factories['history.Listening']()
favorite = factories['favorites.TrackFavorite']()
objects = list(utils.get_activity(user))
assert objects == [favorite, listening]
def test_get_activity_honors_privacy_level(factories, anonymous_user):
listening = factories['history.Listening'](user__privacy_level='me')
favorite1 = factories['favorites.TrackFavorite'](
user__privacy_level='everyone')
favorite2 = factories['favorites.TrackFavorite'](
user__privacy_level='instance')
objects = list(utils.get_activity(anonymous_user))
assert objects == [favorite1]
from django.urls import reverse
from funkwhale_api.activity import serializers
from funkwhale_api.activity import utils
def test_activity_view(factories, api_client, settings, anonymous_user):
settings.API_AUTHENTICATION_REQUIRED = False
favorite = factories['favorites.TrackFavorite'](
user__privacy_level='everyone')
listening = factories['history.Listening']()
url = reverse('api:v1:activity-list')
objects = utils.get_activity(anonymous_user)
serializer = serializers.AutoSerializer(objects, many=True)
response = api_client.get(url)
assert response.status_code == 200
assert response.data['results'] == serializer.data
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment