212 lines
7.0 KiB
Python
212 lines
7.0 KiB
Python
"""
|
|
Views for the score manager application.
|
|
"""
|
|
|
|
import json
|
|
import os
|
|
|
|
from django import forms
|
|
from django.conf import settings
|
|
from django.core.exceptions import PermissionDenied
|
|
from django.http import HttpResponse
|
|
from django.shortcuts import render
|
|
from django.utils.translation import gettext_lazy as _
|
|
|
|
from .models import Piece, Recording, Score, ScoreUserMapping, YoutubeRecording
|
|
|
|
|
|
def manage_repertoire(request):
|
|
"""View for managing the repertoire order and contents."""
|
|
context = {
|
|
"repertoire": Piece.get_repertoire(),
|
|
"allPieces": Piece.objects.all().order_by("title"),
|
|
}
|
|
return render(request, "scoremanager/manage_repertoire.html", context)
|
|
|
|
|
|
def manage_repertoire_ajax_save(request):
|
|
"""AJAX endpoint for saving repertoire order changes."""
|
|
if request.headers.get("X-Requested-With") == "XMLHttpRequest":
|
|
if request.method == "POST":
|
|
try:
|
|
result = json.loads(request.body)
|
|
parsed_result = {int(key): value for (key, value) in result.items()}
|
|
|
|
# Clear all repertoire numbers first
|
|
Piece.objects.all().update(repertoire_nr=None)
|
|
|
|
# Set new repertoire numbers
|
|
for piece in Piece.objects.all():
|
|
if piece.pk in parsed_result:
|
|
piece.repertoire_nr = parsed_result[piece.pk]
|
|
piece.save()
|
|
except (json.JSONDecodeError, ValueError) as e:
|
|
return HttpResponse(f"Error: {e}", status=400)
|
|
|
|
return HttpResponse("OK")
|
|
|
|
|
|
def list_repertoire(request):
|
|
"""View for listing the current repertoire."""
|
|
context = {"repertoire": Piece.get_repertoire()}
|
|
return render(request, "scoremanager/list_repertoire.html", context)
|
|
|
|
|
|
# ----------------------------- Piece View + Ajax views + Forms ------------------------------------------
|
|
|
|
|
|
def score_user_mapping_save(request):
|
|
"""AJAX endpoint for saving a user's preferred score for a piece."""
|
|
if request.headers.get("X-Requested-With") == "XMLHttpRequest":
|
|
if request.method == "POST":
|
|
try:
|
|
result = json.loads(request.body)
|
|
score_id = int(result["myScore"])
|
|
score = Score.objects.get(pk=score_id)
|
|
ScoreUserMapping.add_user_score_mapping(user=request.user, score=score)
|
|
except (
|
|
json.JSONDecodeError,
|
|
KeyError,
|
|
ValueError,
|
|
Score.DoesNotExist,
|
|
) as e:
|
|
return HttpResponse(f"Error: {e}", status=400)
|
|
|
|
return HttpResponse("OK")
|
|
|
|
|
|
def score(request, pk):
|
|
"""View for serving or deleting a score's preview image."""
|
|
try:
|
|
requested_score = Score.objects.get(pk=pk)
|
|
except Score.DoesNotExist:
|
|
return HttpResponse("Score not found", status=404)
|
|
|
|
if request.method == "GET":
|
|
image_file = requested_score.get_image_file()
|
|
image_path = os.path.join(settings.MEDIA_ROOT, image_file)
|
|
|
|
try:
|
|
with open(image_path, "rb") as f:
|
|
image_data = f.read()
|
|
return HttpResponse(image_data, content_type="image/jpeg")
|
|
except FileNotFoundError:
|
|
return HttpResponse("Image not found", status=404)
|
|
|
|
if request.method == "DELETE":
|
|
if not (
|
|
requested_score.uploaded_by == request.user
|
|
or request.user.has_perm("scoremanager.manage_scores")
|
|
):
|
|
raise PermissionDenied
|
|
requested_score.delete()
|
|
return HttpResponse("OK")
|
|
|
|
return HttpResponse("Method not allowed", status=405)
|
|
|
|
|
|
def youtube_link(request):
|
|
"""AJAX endpoint for adding or deleting YouTube links."""
|
|
try:
|
|
result = json.loads(request.body)
|
|
except json.JSONDecodeError:
|
|
return HttpResponse("Invalid JSON", status=400)
|
|
|
|
if request.method == "DELETE":
|
|
try:
|
|
link_id = int(result["linkid"])
|
|
youtube_recording = YoutubeRecording.objects.get(pk=link_id)
|
|
|
|
if youtube_recording.uploaded_by == request.user or request.user.has_perm(
|
|
"scoremanager.manage_scores"
|
|
):
|
|
youtube_recording.delete()
|
|
else:
|
|
raise PermissionDenied
|
|
|
|
return HttpResponse("OK")
|
|
except (KeyError, ValueError, YoutubeRecording.DoesNotExist) as e:
|
|
return HttpResponse(f"Error: {e}", status=400)
|
|
|
|
elif request.method == "POST":
|
|
try:
|
|
link = str(result["link"])
|
|
piece_id = int(result["pieceId"])
|
|
piece = Piece.objects.get(pk=piece_id)
|
|
|
|
new_recording = YoutubeRecording(piece=piece, link=link)
|
|
new_recording.uploaded_by = request.user
|
|
new_recording.save()
|
|
return HttpResponse("OK")
|
|
except (KeyError, ValueError, Piece.DoesNotExist) as e:
|
|
return HttpResponse(f"Error: {e}", status=400)
|
|
|
|
return HttpResponse("Method not allowed", status=405)
|
|
|
|
|
|
class UploadFileForm(forms.Form):
|
|
"""Form for uploading score and recording files."""
|
|
|
|
file = forms.FileField(max_length=80)
|
|
|
|
def clean_file(self):
|
|
f = self.cleaned_data["file"]
|
|
extension = os.path.splitext(f.name)[1].lower()
|
|
allowed_extensions = [".pdf", ".mp3", ".zip"]
|
|
|
|
if extension not in allowed_extensions:
|
|
raise forms.ValidationError(
|
|
_("Unknown extension. Allowed extensions are mp3, pdf and zip")
|
|
)
|
|
|
|
return f
|
|
|
|
|
|
def piece_view(request, pk):
|
|
"""View for displaying a piece's details and handling file uploads."""
|
|
try:
|
|
current_piece = Piece.objects.get(pk=pk)
|
|
except Piece.DoesNotExist:
|
|
return HttpResponse("Piece not found", status=404)
|
|
|
|
context = {"piece": current_piece}
|
|
|
|
# Find active score for user
|
|
for score_obj in current_piece.scores.all():
|
|
if score_obj.is_active_score(request.user):
|
|
context["activeScore"] = score_obj
|
|
context["pictureScore"] = score_obj
|
|
break
|
|
|
|
# Fall back to first score if no active score
|
|
if "pictureScore" not in context and current_piece.scores.exists():
|
|
context["pictureScore"] = current_piece.scores.first()
|
|
|
|
if request.method == "POST":
|
|
form = UploadFileForm(request.POST, request.FILES)
|
|
|
|
if form.is_valid():
|
|
f = request.FILES["file"]
|
|
basename, extension = os.path.splitext(f.name)
|
|
extension = extension.lower()
|
|
|
|
if extension == ".mp3":
|
|
recording = Recording(piece=current_piece, artist=basename, file=f)
|
|
recording.uploaded_by = request.user
|
|
recording.save()
|
|
|
|
elif extension == ".pdf":
|
|
score_obj = Score(piece=current_piece, score_type=basename, file=f)
|
|
score_obj.uploaded_by = request.user
|
|
score_obj.save()
|
|
|
|
elif extension == ".zip":
|
|
# TODO: Handle zip file uploads
|
|
pass
|
|
else:
|
|
form = UploadFileForm()
|
|
|
|
context["form"] = form
|
|
|
|
return render(request, "scoremanager/piece_view.html", context)
|