Files
dss.api/api/views.py
2015-07-31 22:53:15 +01:00

278 lines
9.6 KiB
Python
Executable File

import logging
import os
from django.core.exceptions import PermissionDenied, ObjectDoesNotExist
from django.core.files.base import ContentFile
from django.core.files.storage import FileSystemStorage, default_storage
from django.db.models import Count
from django.http.response import HttpResponse
from rest_framework import viewsets
from rest_framework import views
from rest_framework.decorators import detail_route
from rest_framework.permissions import BasePermission
from rest_framework.parsers import FileUploadParser
from rest_framework.permissions import IsAuthenticated, IsAuthenticatedOrReadOnly
from rest_framework.response import Response
from rest_framework.status import HTTP_202_ACCEPTED, HTTP_401_UNAUTHORIZED, HTTP_400_BAD_REQUEST, HTTP_404_NOT_FOUND, \
HTTP_200_OK, HTTP_204_NO_CONTENT
from api import serializers
from core.utils import cdn
from dss import settings
from spa.tasks import create_waveform_task, upload_to_cdn_task
from spa.models.genre import Genre
from spa.models.activity import ActivityPlay
from spa.models.mix import Mix
from spa.models.comment import Comment
from spa.models.notification import Notification
from spa.models.userprofile import UserProfile
logger = logging.getLogger('spa')
class AnonymousWriteUserDelete(BasePermission):
def has_permission(self, request, view):
return True
def has_object_permission(self, request, view, obj):
return True
class CommentViewSet(viewsets.ModelViewSet):
queryset = Comment.objects.all()
serializer_class = serializers.CommentSerializer
permission_classes = (AnonymousWriteUserDelete,)
filter_fields = (
'comment',
'mix__slug',
)
ordering_fields = (
'id',
)
def perform_create(self, serializer):
if 'mix_id' in self.request.data:
try:
mix = Mix.objects.get(pk=self.request.data['mix_id'])
if mix is not None:
serializer.save(
mix=mix,
user=self.request.user if self.request.user.is_authenticated() else None
)
except Mix.DoesNotExist:
pass
except Exception, ex:
pass
class UserProfileViewSet(viewsets.ModelViewSet):
queryset = UserProfile.objects.annotate(mix_count=Count('mixes')).order_by('-mix_count')
serializer_class = serializers.UserProfileSerializer
permission_classes = (IsAuthenticatedOrReadOnly,)
lookup_field = 'slug'
filter_fields = (
'slug',
)
def get_queryset(self):
if 'following' in self.request.query_params:
ret = UserProfile.objects.filter(following__slug__in=[self.request.query_params['following']])
elif 'followers' in self.request.query_params:
ret = UserProfile.objects.filter(followers__slug__in=[self.request.query_params['followers']])
else:
ret = super(UserProfileViewSet, self).get_queryset()
return ret
class MixViewSet(viewsets.ModelViewSet):
queryset = Mix.objects.all()
serializer_class = serializers.MixSerializer
permission_classes = (IsAuthenticatedOrReadOnly,)
lookup_field = 'slug'
filter_fields = (
'waveform_generated',
'slug',
'user__slug',
'is_featured',
)
@detail_route()
def stream_url(self, request, **kwargs):
mix = self.get_object()
return Response({'url': mix.get_stream_url()})
def get_queryset(self):
if 'friends' in self.request.query_params:
if self.request.user.is_authenticated():
rows = Mix.objects.filter(user__in=self.request.user.userprofile.following.all())
return rows
else:
raise PermissionDenied("Not allowed")
else:
return Mix.objects.all()
def perform_create(self, serializer):
serializer.save(user=self.request.user.userprofile)
class AttachedImageUploadView(views.APIView):
parser_classes = (FileUploadParser,)
def post(self, request):
if request.data['file'] is None or request.data.get('data') is None:
return Response(status=HTTP_400_BAD_REQUEST)
file_obj = request.data['file']
file_hash = request.data.get('data')
try:
mix = Mix.objects.get(uid=file_hash)
if mix:
mix.mix_image = file_obj
mix.save()
return Response(HTTP_202_ACCEPTED)
except ObjectDoesNotExist:
return Response(status=HTTP_404_NOT_FOUND)
except Exception, ex:
logger.exception(ex)
return Response(status=HTTP_401_UNAUTHORIZED)
class SearchResultsView(views.APIView):
def get(self, request, format=None):
q = request.GET.get('q', '')
if len(q) > 0:
m = [{
'title': mix.title,
'image': mix.get_image_url(),
'slug': mix.slug,
'url': mix.get_absolute_url(),
'description': mix.description
} for mix in Mix.objects.filter(title__icontains=q)[0:10]]
return Response(m)
return HttpResponse(status=HTTP_204_NO_CONTENT)
class PartialMixUploadView(views.APIView):
parser_classes = (FileUploadParser,)
permission_classes = (IsAuthenticated,)
# noinspection PyBroadException
def post(self, request):
try:
logger.info("Received post file")
uid = request.META.get('HTTP_UPLOAD_HASH')
in_file = request.data['file'] if request.data else None
file_name, extension = os.path.splitext(in_file.name)
logger.info("Constructing storage")
file_storage = FileSystemStorage(location=os.path.join(settings.CACHE_ROOT, "mixes"))
cache_file = file_storage.save("%s%s" % (uid, extension), ContentFile(in_file.read()))
response = 'File creation in progress'
logger.info("Storage constructed")
try:
logger.debug("Received input file")
logger.debug("Storage is {0}".format(file_storage.base_location))
input_file = os.path.join(file_storage.base_location, cache_file)
# Chain the waveform & archive tasks together
# Probably not the best place for them but will do for now
# First argument to upload_to_cdn_task is not specified as it is piped from create_waveform_task
logger.debug("Processing input_file: {0}".format(input_file))
logger.debug("Connecting to broker: {0}".format(settings.BROKER_URL))
from celery import group
(create_waveform_task.s(input_file, uid) |
group(
upload_to_cdn_task.s(filetype='mp3', uid=uid, container_name='mixes'),
upload_to_cdn_task.s(filetype='png', uid=uid, container_name='waveforms')
)
).delay()
logger.debug("Waveform task started")
except Exception, ex:
logger.exception(ex)
response = \
'Unable to connect to rabbitmq, there may be a delay in getting your mix online'
file_dict = {
'response': response,
'size': in_file.size,
'uid': uid
}
return Response(file_dict, HTTP_202_ACCEPTED)
except Exception, ex:
logger.exception(ex.message)
raise
class HitlistViewSet(viewsets.ModelViewSet):
queryset = UserProfile.objects.all().annotate(mix_count=Count('mixes')).order_by('-mix_count')[0:10]
serializer_class = serializers.HitlistSerializer
class ActivityViewSet(viewsets.ModelViewSet):
queryset = ActivityPlay.objects.all() # select_subclasses()
serializer_class = serializers.ActivitySerializer
def get_queryset(self):
user = self.request.user
if not user.is_authenticated():
raise PermissionDenied("Not allowed")
ret = ActivityPlay.objects.filter(mix__user=user).order_by("-id")
if len(ret) > 0:
logger.debug("Activity returned: {0}".format(ret[0].get_object_slug()))
return ret
else:
return []
class DownloadItemView(views.APIView):
def get(self, request, *args, **kwargs):
try:
mix = Mix.objects.get(uid=request.query_params['uid'])
return Response({'url': mix.get_download_url()}, HTTP_200_OK)
except ObjectDoesNotExist:
return Response("Not Found", HTTP_404_NOT_FOUND)
class NotificationViewSet(viewsets.ModelViewSet):
queryset = Notification.objects.all()
serializer_class = serializers.NotificationSerializer
def get_queryset(self):
user = self.request.user
if not user.is_authenticated():
raise PermissionDenied("Not allowed")
return Notification.objects.filter(to_user=user).order_by('-date')[0:5]
class GenreViewSet(viewsets.ModelViewSet):
queryset = Genre.objects.all()
serializer_class = serializers.GenreSerializer
def get_queryset(self):
if 'q' in self.request.query_params:
rows = Genre.objects \
.annotate(used=Count('mix')) \
.filter(description__icontains=self.request.query_params['q']) \
.only('description') \
.order_by('-used')
return rows
else:
rows = Genre.objects \
.annotate(used=Count('mix')) \
.only('description') \
.order_by('-used')
return rows