import time from functools import wraps import django.middleware.csrf as csrf from django.contrib.auth import authenticate, login from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger from django.db.models import Q from django.http import JsonResponse, HttpResponseForbidden from django.shortcuts import get_object_or_404 from django.views.decorators.http import require_http_methods from mutagen import File from marietje.utils import song_to_dict, playlist_song_to_dict, send_to_bertha from queues.models import PlaylistSong, QueueCommand from songs.models import Song def api_auth_required(view_func): @wraps(view_func) def _wrapped_view(request, *args, **kwargs): if request.user.is_authenticated and request.user.is_active: return view_func(request, *args, **kwargs) response = JsonResponse({ 'error': 'User not authenticated or activated.' }) response.status_code = 401 return response return _wrapped_view def login_user(request): data = {'error': 'Method not allowed'} status = 405 if request.method == "POST": username = request.POST.get('username', '').strip() password = request.POST.get('password', '').strip() data = {'error': 'Please enter a correct username and password. ' 'Note that both fields may be case-sensitive.'} status = 401 if username and password: user = authenticate(username=username, password=password) if user is not None: if user.is_active: login(request, user) data = {} status = 200 else: data = {'error': 'User is not active'} status = 401 else: csrf.get_token(request) response = JsonResponse(data) response.status_code = status return response @api_auth_required def permissions(request): return JsonResponse({ 'can_move': request.user.has_perm('queues.can_move'), 'can_skip': request.user.has_perm('queues.can_skip'), 'can_cancel': request.user.has_perm('queues.can_cancel'), 'can_control_volume': request.user.has_perm('queues.can_control_volume') }) @api_auth_required def songs(request): try: pagesize = int(request.POST.get('pagesize')) except: pagesize = 10 if not pagesize or pagesize < 10: pagesize = 10 try: page = int(request.POST.get('page')) except: page = 1 queries = [Q(deleted=False)] queries.extend([Q(Q(artist__icontains=word) | Q(title__icontains=word)) for word in request.POST.get('all', '').split()]) queries.extend([Q(user__name__icontains=word) for word in request.POST.get('uploader', '').split()]) filter_query = queries.pop() for query in queries: filter_query &= query songs_query = Song.objects.filter(filter_query).order_by('artist', 'title').select_related('user') paginator = Paginator(songs_query, pagesize) try: songs = paginator.page(page) except PageNotAnInteger: songs = paginator.page(1) except EmptyPage: songs = paginator.page(paginator.num_pages) songs_dict = [song_to_dict(song, user=True) for song in songs.object_list] return JsonResponse({ 'per_page': pagesize, 'current_page': page, 'last_page': paginator.num_pages, 'data': songs_dict }) @api_auth_required def managesongs(request): try: pagesize = int(request.POST.get('pagesize')) except: pagesize = 10 if not pagesize or pagesize < 10: pagesize = 10 try: page = int(request.POST.get('page')) except: page = 1 songs_query = Song.objects.filter( user=request.user, deleted=False, artist__icontains=request.POST.get('artist', ''), title__icontains=request.POST.get('title', '') ).order_by('artist', 'title') total = songs_query.count() paginator = Paginator(songs_query, pagesize) try: songs = paginator.page(page) except PageNotAnInteger: songs = paginator.page(1) except EmptyPage: songs = paginator.page(paginator.num_pages) songs_dict = [song_to_dict(song) for song in songs.object_list] return JsonResponse({ 'total': total, 'per_page': pagesize, 'current_page': page, 'last_page': paginator.num_pages, 'data': songs_dict }) @api_auth_required def queue(request): queue = request.user.queue return JsonResponse({ 'current_song': playlist_song_to_dict(queue.current_song()), 'queue': [playlist_song_to_dict(playlist_song, user=request.user) for playlist_song in queue.queue()], 'started_at': 0 if queue.started_at is None else int(time.mktime(queue.started_at.timetuple())), 'current_time': int(time.time()) }) @api_auth_required def skip(request): playlist_song = request.user.queue.current_song() if playlist_song.user != request.user and not request.user.has_perm('queues.can_skip'): return HttpResponseForbidden() playlist_song.state = 2 playlist_song.save() return JsonResponse({}) @require_http_methods(["POST"]) @api_auth_required def move_up(request): if not request.user.has_perm('queues.can_move'): return HttpResponseForbidden() playlist_song = get_object_or_404(PlaylistSong, id=request.POST.get('id')) playlist_song.move_up() return JsonResponse({}) @require_http_methods(["POST"]) @api_auth_required def move_down(request): playlist_song = get_object_or_404(PlaylistSong, id=request.POST.get('id')) if playlist_song.user != request.user and not request.user.has_perm('queues.can_move'): return HttpResponseForbidden() playlist_song.move_down() return JsonResponse({}) @require_http_methods(["POST"]) @api_auth_required def cancel(request): playlist_song = get_object_or_404(PlaylistSong, id=request.POST.get('id')) if playlist_song.user != request.user and not request.user.has_perm('queues.can_cancel'): return HttpResponseForbidden() playlist_song.state = 3 playlist_song.save() return JsonResponse({}) @require_http_methods(["POST"]) @api_auth_required def request(request): queue = request.user.queue song = get_object_or_404(Song, id=request.POST.get('id'), deleted=False) queue.request(song, request.user) return JsonResponse({ 'success': True }) @require_http_methods(["POST"]) @api_auth_required def upload(request): files = request.FILES.getlist('file[]') artists = request.POST.getlist('artist[]') titles = request.POST.getlist('title[]') for artist in artists: if not artist: return JsonResponse({'success': False, 'errorMessage': 'Please enter artists which are not empty.'}) for title in titles: if not title: return JsonResponse({'success': False, 'errorMessage': 'Please enter titles which are not empty.'}) for i, file in enumerate(files): duration = File(file).info.length hash = send_to_bertha(file) if not hash: return JsonResponse({'success': False, 'errorMessage': 'Files not uploaded correctly.'}) song = Song(user=request.user, artist=artists[i], title=titles[i], hash=hash, duration=duration) song.save() return JsonResponse({'success': True}) @require_http_methods(["POST"]) @api_auth_required def volume_down(request): if not request.user.has_perm('queues.can_control_volume'): return HttpResponseForbidden() command = QueueCommand(queue=request.user.queue, command='volume_down') command.save() return JsonResponse({}) @require_http_methods(["POST"]) @api_auth_required def volume_up(request): if not request.user.has_perm('queues.can_control_volume'): return HttpResponseForbidden() command = QueueCommand(queue=request.user.queue, command='volume_up') command.save() return JsonResponse({})