from rest_framework import viewsets, status from rest_framework.decorators import action from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response from .models import LeistungstestTemplate, LeistungstestTemplateExercise, LeistungstestResult, LeistungstestResultItem from .serializers import ( LeistungstestTemplateSerializer, LeistungstestTemplateExerciseSerializer, LeistungstestResultSerializer, LeistungstestResultItemSerializer, ) from .stats import get_template_leaderboard, get_exercise_leaderboard, get_used_exercises class LeistungstestTemplateViewSet(viewsets.ModelViewSet): queryset = LeistungstestTemplate.objects.all() serializer_class = LeistungstestTemplateSerializer def get_queryset(self): return LeistungstestTemplate.objects.all().prefetch_related('exercises__exercise') def create(self, request, *args, **kwargs): name = request.data.get('name') exercises_data = request.data.get('exercises', []) # Create template first template = LeistungstestTemplate.objects.create(name=name) # Create exercises for i, ex_data in enumerate(exercises_data): LeistungstestTemplateExercise.objects.create( template=template, exercise_id=ex_data['exercise'], target_reps=ex_data['target_reps'], order=ex_data.get('order', i), ) # Reload with prefetch to get exercise names template = LeistungstestTemplate.objects.prefetch_related('exercises__exercise').get(pk=template.pk) return Response( LeistungstestTemplateSerializer(template).data, status=status.HTTP_201_CREATED ) @action(detail=True, methods=['post']) def duplicate(self, request, pk=None): template = self.get_object() new_template = LeistungstestTemplate.objects.create(name=f"{template.name} (Kopie)") for exercise in template.exercises.all(): LeistungstestTemplateExercise.objects.create( template=new_template, exercise=exercise.exercise, target_reps=exercise.target_reps, order=exercise.order, ) return Response( LeistungstestTemplateSerializer(new_template).data, status=status.HTTP_201_CREATED ) def update(self, request, *args, **kwargs): partial = kwargs.pop('partial', False) instance = self.get_object() instance.name = request.data.get('name', instance.name) instance.save() exercises_data = request.data.get('exercises') if exercises_data is not None: instance.exercises.all().delete() for i, ex_data in enumerate(exercises_data): LeistungstestTemplateExercise.objects.create( template=instance, exercise_id=ex_data['exercise'], target_reps=ex_data['target_reps'], order=ex_data.get('order', i), ) instance = LeistungstestTemplate.objects.prefetch_related('exercises__exercise').get(pk=instance.pk) return Response(LeistungstestTemplateSerializer(instance).data) class LeistungstestTemplateExerciseViewSet(viewsets.ModelViewSet): queryset = LeistungstestTemplateExercise.objects.all() serializer_class = LeistungstestTemplateExerciseSerializer class LeistungstestResultViewSet(viewsets.ModelViewSet): queryset = LeistungstestResult.objects.all() serializer_class = LeistungstestResultSerializer def get_queryset(self): queryset = LeistungstestResult.objects.all().prefetch_related('items__exercise') template_id = self.request.query_params.get('template') wrestler_id = self.request.query_params.get('wrestler') if template_id: queryset = queryset.filter(template_id=template_id) if wrestler_id: queryset = queryset.filter(wrestler_id=wrestler_id) return queryset def create(self, request, *args, **kwargs): template_id = request.data.get('template') wrestler_id = request.data.get('wrestler') items_data = request.data.get('items', []) result = LeistungstestResult.objects.create( template_id=template_id, wrestler_id=wrestler_id, total_time_seconds=request.data.get('total_time_seconds') or None, rating=request.data.get('rating', 3), notes=request.data.get('notes', ''), ) for i, item_data in enumerate(items_data): LeistungstestResultItem.objects.create( result=result, exercise_id=item_data['exercise'], target_reps=item_data.get('target_reps', 0), actual_reps=item_data.get('actual_reps', 0), elapsed_seconds=item_data.get('elapsed_seconds', 0), order=item_data.get('order', i), ) result_items = LeistungstestResultItem.objects.filter(result=result) total_target = sum(item.target_reps for item in result_items) total_actual = sum(item.actual_reps for item in result_items) if total_target > 0: score = round((total_actual / total_target) * 100, 1) else: score = 0.0 result.refresh_from_db() result_data = LeistungstestResultSerializer(result).data result_data['score_percent'] = score return Response(result_data, status=status.HTTP_201_CREATED) def update(self, request, *args, **kwargs): partial = kwargs.pop('partial', False) instance = self.get_object() instance.total_time_seconds = request.data.get('total_time_seconds', instance.total_time_seconds) instance.rating = request.data.get('rating', instance.rating) instance.notes = request.data.get('notes', instance.notes) instance.save() items_data = request.data.get('items') if items_data is not None: instance.items.all().delete() for i, item_data in enumerate(items_data): LeistungstestResultItem.objects.create( result=instance, exercise_id=item_data['exercise'], target_reps=item_data.get('target_reps', 0), actual_reps=item_data.get('actual_reps', 0), elapsed_seconds=item_data.get('elapsed_seconds', 0), order=item_data.get('order', i), ) result_items = LeistungstestResultItem.objects.filter(result=instance) total_target = sum(item.target_reps for item in result_items) total_actual = sum(item.actual_reps for item in result_items) if total_target > 0: score = round((total_actual / total_target) * 100, 1) else: score = 0.0 result_data = LeistungstestResultSerializer(instance).data result_data['score_percent'] = score return Response(result_data) @action(detail=False, methods=['get']) def leaderboard(self, request): template_id = request.query_params.get('template') if not template_id: return Response( {'error': 'template parameter is required'}, status=status.HTTP_400_BAD_REQUEST ) limit = int(request.query_params.get('limit', 10)) results = LeistungstestResult.objects.filter(template_id=template_id)\ .select_related('wrestler') leaderboard_data = [] for result in results: leaderboard_data.append({ 'rank': 0, 'result_id': result.id, 'wrestler_id': result.wrestler.id, 'wrestler_name': str(result.wrestler), 'score_percent': result.score_percent, 'completed_at': result.completed_at, 'total_time_seconds': result.total_time_seconds, 'rating': result.rating, }) leaderboard_data.sort(key=lambda x: x['score_percent'], reverse=True) leaderboard_data = leaderboard_data[:limit] for i, entry in enumerate(leaderboard_data, 1): entry['rank'] = i return Response(leaderboard_data) class LeistungstestResultItemViewSet(viewsets.ModelViewSet): queryset = LeistungstestResultItem.objects.all() serializer_class = LeistungstestResultItemSerializer class LeistungstestStatsViewSet(viewsets.ViewSet): permission_classes = [IsAuthenticated] @action(detail=False, methods=['get']) def leaderboard(self, request): lb_type = request.query_params.get('type', 'template') template_id = request.query_params.get('template_id') exercise_id = request.query_params.get('exercise_id') period = request.query_params.get('period', 'all') limit = int(request.query_params.get('limit', 10)) if lb_type == 'template' and template_id: results = get_template_leaderboard(int(template_id), period, limit) template = LeistungstestTemplate.objects.get(pk=template_id) return Response({ 'template_id': template_id, 'template_name': template.name, 'period': period, 'results': results, }) elif lb_type == 'exercise' and exercise_id: from exercises.models import Exercise results = get_exercise_leaderboard(int(exercise_id), period, limit) exercise = Exercise.objects.get(pk=exercise_id) return Response({ 'exercise_id': exercise_id, 'exercise_name': exercise.name, 'period': period, 'results': results, }) return Response({'error': 'Invalid parameters'}, status=400) @action(detail=False, methods=['get']) def exercises(self, request): exercises = get_used_exercises() return Response([{'id': e.id, 'name': e.name} for e in exercises])