3fefc550fe
- Django backend with DRF (clubs, wrestlers, trainers, exercises, templates, trainings, homework, locations, leistungstest) - Next.js 16 frontend with React, Shadcn UI, Tailwind - JWT authentication - Full CRUD for all entities - Calendar view for trainings - Homework management system - Leistungstest tracking
238 lines
9.4 KiB
Python
238 lines
9.4 KiB
Python
from rest_framework import viewsets, filters, status
|
|
from rest_framework.decorators import action
|
|
from rest_framework.permissions import IsAuthenticated
|
|
from rest_framework.response import Response
|
|
from django_filters.rest_framework import DjangoFilterBackend
|
|
from django.utils import timezone
|
|
from django.db import transaction
|
|
|
|
from utils.permissions import ClubLevelPermission, ClubFilterBackend
|
|
from .models import (
|
|
Homework, HomeworkExerciseItem, HomeworkAssignment,
|
|
HomeworkAssignmentItem, HomeworkStatus,
|
|
TrainingHomeworkAssignment, TrainingHomeworkExerciseItem
|
|
)
|
|
from .serializers import (
|
|
HomeworkSerializer, HomeworkDetailSerializer, HomeworkExerciseItemSerializer,
|
|
HomeworkAssignmentSerializer, HomeworkAssignmentListSerializer,
|
|
AssignHomeworkSerializer, CompleteItemSerializer, HomeworkStatusSerializer,
|
|
TrainingHomeworkAssignmentSerializer, TrainingHomeworkAssignmentCreateSerializer
|
|
)
|
|
from wrestleDesk.pagination import StandardResultsSetPagination
|
|
|
|
|
|
class HomeworkViewSet(viewsets.ModelViewSet):
|
|
queryset = Homework.objects.prefetch_related('exercise_items', 'exercise_items__exercise').all()
|
|
serializer_class = HomeworkSerializer
|
|
pagination_class = StandardResultsSetPagination
|
|
permission_classes = [IsAuthenticated]
|
|
filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
|
|
filterset_fields = ['club', 'is_active']
|
|
search_fields = ['title', 'description']
|
|
ordering_fields = ['created_at', 'due_date']
|
|
|
|
def get_serializer_class(self):
|
|
if self.action == 'retrieve':
|
|
return HomeworkDetailSerializer
|
|
return HomeworkSerializer
|
|
|
|
|
|
class HomeworkExerciseItemViewSet(viewsets.ModelViewSet):
|
|
queryset = HomeworkExerciseItem.objects.select_related('homework', 'exercise').all()
|
|
serializer_class = HomeworkExerciseItemSerializer
|
|
pagination_class = StandardResultsSetPagination
|
|
permission_classes = [IsAuthenticated]
|
|
filter_backends = [DjangoFilterBackend]
|
|
filterset_fields = ['homework']
|
|
|
|
|
|
class HomeworkAssignmentViewSet(viewsets.ModelViewSet):
|
|
queryset = HomeworkAssignment.objects.select_related('homework', 'wrestler', 'club').prefetch_related('items').all()
|
|
serializer_class = HomeworkAssignmentSerializer
|
|
pagination_class = StandardResultsSetPagination
|
|
permission_classes = [IsAuthenticated]
|
|
filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
|
|
filterset_fields = ['homework', 'wrestler', 'club', 'is_completed']
|
|
search_fields = ['wrestler__first_name', 'wrestler__last_name']
|
|
ordering_fields = ['created_at', 'due_date']
|
|
|
|
def get_serializer_class(self):
|
|
if self.action == 'list':
|
|
return HomeworkAssignmentListSerializer
|
|
return HomeworkAssignmentSerializer
|
|
|
|
@action(detail=True, methods=['post'])
|
|
@transaction.atomic
|
|
def complete_item(self, request, pk=None):
|
|
serializer = CompleteItemSerializer(data=request.data)
|
|
if not serializer.is_valid():
|
|
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
assignment = self.get_object()
|
|
item_id = serializer.validated_data['item_id']
|
|
|
|
try:
|
|
item = assignment.items.get(id=item_id)
|
|
except HomeworkAssignmentItem.DoesNotExist:
|
|
return Response(
|
|
{'detail': 'Item not found'},
|
|
status=status.HTTP_404_NOT_FOUND
|
|
)
|
|
|
|
item.is_completed = True
|
|
item.completion_date = timezone.now()
|
|
item.save()
|
|
|
|
return Response({'status': 'item completed'})
|
|
|
|
@action(detail=False, methods=['post'])
|
|
@transaction.atomic
|
|
def assign(self, request):
|
|
serializer = AssignHomeworkSerializer(data=request.data)
|
|
if not serializer.is_valid():
|
|
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
homework_id = serializer.validated_data['homework']
|
|
wrestler_ids = serializer.validated_data['wrestlers']
|
|
due_date = serializer.validated_data.get('due_date')
|
|
notes = serializer.validated_data.get('notes', '')
|
|
|
|
try:
|
|
homework = Homework.objects.get(id=homework_id)
|
|
except Homework.DoesNotExist:
|
|
return Response({'detail': 'Homework not found'}, status=status.HTTP_404_NOT_FOUND)
|
|
|
|
created_assignments = []
|
|
errors = []
|
|
|
|
for wrestler_id in wrestler_ids:
|
|
try:
|
|
existing = HomeworkAssignment.objects.filter(
|
|
homework=homework,
|
|
wrestler_id=wrestler_id
|
|
).exists()
|
|
|
|
if existing:
|
|
errors.append(f"Wrestler {wrestler_id} hat bereits diese Hausaufgabe")
|
|
continue
|
|
|
|
assignment = HomeworkAssignment.objects.create(
|
|
homework=homework,
|
|
wrestler_id=wrestler_id,
|
|
club=homework.club,
|
|
due_date=due_date,
|
|
notes=notes
|
|
)
|
|
|
|
# Copy exercises from homework to assignment
|
|
for exercise_item in homework.exercise_items.all():
|
|
HomeworkAssignmentItem.objects.create(
|
|
assignment=assignment,
|
|
exercise=exercise_item.exercise
|
|
)
|
|
|
|
created_assignments.append(assignment.id)
|
|
|
|
except Exception as e:
|
|
errors.append(f"Wrestler {wrestler_id}: {str(e)}")
|
|
|
|
return Response({
|
|
'created': created_assignments,
|
|
'errors': errors
|
|
})
|
|
|
|
|
|
class HomeworkStatusViewSet(viewsets.ModelViewSet):
|
|
queryset = HomeworkStatus.objects.select_related('homework', 'wrestler').all()
|
|
serializer_class = HomeworkStatusSerializer
|
|
pagination_class = StandardResultsSetPagination
|
|
permission_classes = [IsAuthenticated]
|
|
filter_backends = [DjangoFilterBackend, filters.OrderingFilter]
|
|
filterset_fields = ['homework', 'wrestler', 'is_completed']
|
|
ordering_fields = ['created_at', 'completion_date']
|
|
|
|
|
|
# NEUES SYSTEM: Training-basierte Homework
|
|
|
|
class TrainingHomeworkAssignmentViewSet(viewsets.ModelViewSet):
|
|
permission_classes = [IsAuthenticated]
|
|
filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
|
|
serializer_class = TrainingHomeworkAssignmentSerializer
|
|
filterset_fields = ['is_completed', 'training', 'wrestler']
|
|
search_fields = ['wrestler__first_name', 'wrestler__last_name']
|
|
ordering_fields = ['created_at', 'is_completed']
|
|
http_method_names = ['get', 'post', 'patch', 'delete']
|
|
|
|
def get_queryset(self):
|
|
queryset = TrainingHomeworkAssignment.objects.select_related(
|
|
'training', 'wrestler'
|
|
).prefetch_related(
|
|
'exercises', 'exercises__exercise'
|
|
).all()
|
|
|
|
# Filter by training ID if provided
|
|
training_id = self.request.query_params.get('training')
|
|
if training_id:
|
|
queryset = queryset.filter(training_id=training_id)
|
|
|
|
return queryset
|
|
|
|
def get_serializer_class(self):
|
|
if self.action == 'create':
|
|
return TrainingHomeworkAssignmentCreateSerializer
|
|
return TrainingHomeworkAssignmentSerializer
|
|
|
|
@action(detail=True, methods=['post'])
|
|
def complete(self, request, pk=None):
|
|
assignment = self.get_object()
|
|
assignment.is_completed = True
|
|
assignment.completion_date = timezone.now().date()
|
|
assignment.save()
|
|
# Also mark all exercises as completed
|
|
assignment.exercises.update(is_completed=True)
|
|
serializer = self.get_serializer(assignment)
|
|
return Response(serializer.data)
|
|
|
|
@action(detail=True, methods=['post'])
|
|
def uncomplete(self, request, pk=None):
|
|
assignment = self.get_object()
|
|
assignment.is_completed = False
|
|
assignment.completion_date = None
|
|
assignment.save()
|
|
# Also mark all exercises as not completed
|
|
assignment.exercises.update(is_completed=False)
|
|
serializer = self.get_serializer(assignment)
|
|
return Response(serializer.data)
|
|
|
|
@action(detail=True, methods=['post'])
|
|
def complete_exercise(self, request, pk=None):
|
|
assignment = self.get_object()
|
|
exercise_id = request.data.get('exercise_id')
|
|
|
|
if not exercise_id:
|
|
return Response({'detail': 'exercise_id is required'}, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
try:
|
|
item = assignment.exercises.get(id=exercise_id)
|
|
item.is_completed = True
|
|
item.save()
|
|
return Response({'status': 'exercise completed'})
|
|
except TrainingHomeworkExerciseItem.DoesNotExist:
|
|
return Response({'detail': 'Exercise not found'}, status=status.HTTP_404_NOT_FOUND)
|
|
|
|
@action(detail=True, methods=['post'])
|
|
def uncomplete_exercise(self, request, pk=None):
|
|
assignment = self.get_object()
|
|
exercise_id = request.data.get('exercise_id')
|
|
|
|
if not exercise_id:
|
|
return Response({'detail': 'exercise_id is required'}, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
try:
|
|
item = assignment.exercises.get(id=exercise_id)
|
|
item.is_completed = False
|
|
item.save()
|
|
return Response({'status': 'exercise uncompleted'})
|
|
except TrainingHomeworkExerciseItem.DoesNotExist:
|
|
return Response({'detail': 'Exercise not found'}, status=status.HTTP_404_NOT_FOUND)
|