""" All API views that are used to retrieve data from the database. They can be categorized by the permissions they require. All views require a user to be authenticated and most are only accessible by one user group """ import logging from django.conf import settings from django.db.models import Avg from rest_framework import generics, mixins, viewsets, status from rest_framework.decorators import api_view, list_route from rest_framework.response import Response from core import models from core.models import ExamType, StudentInfo, SubmissionType from core.permissions import IsReviewer, IsStudent, IsTutorOrReviewer from core.serializers import (ExamSerializer, StudentInfoSerializer, StudentInfoSerializerForListView, SubmissionNoTypeSerializer, SubmissionSerializer, SubmissionTypeSerializer, TutorSerializer) log = logging.getLogger(__name__) @api_view() def get_jwt_expiration_delta(request): return Response({'timeDelta': settings.JWT_AUTH['JWT_EXPIRATION_DELTA']}) @api_view() def get_user_role(request): return Response({'role': request.user.role}) class StudentSelfApiView(generics.RetrieveAPIView): """ Gets all data that belongs to one student """ permission_classes = (IsStudent,) serializer_class = StudentInfoSerializer def get_object(self) -> StudentInfo: """ The object in question is the student associated with the requests user. Since the permission IsStudent is satisfied the member exists """ if self.request.user.is_superuser: return StudentInfo.objects.last() return self.request.user.student class StudentSelfSubmissionsApiView(generics.ListAPIView): permission_classes = (IsStudent, ) serializer_class = SubmissionSerializer def get_queryset(self): return self.request.user.student.submissions class StudentReviewerApiViewSet(viewsets.ReadOnlyModelViewSet): """ Gets a list of all students without individual submissions """ permission_classes = (IsReviewer,) queryset = StudentInfo.objects\ .select_related('user')\ .select_related('exam')\ .prefetch_related('submissions')\ .prefetch_related('submissions__feedback')\ .prefetch_related('submissions__type')\ .all() serializer_class = StudentInfoSerializerForListView def _set_students_active(self, active): for student in self.get_queryset(): user = student.user user.is_active = active user.save() @list_route(methods=['post']) def deactivate(self, request): self._set_students_active(False) return Response(status=status.HTTP_200_OK) @list_route(methods=['post']) def activate(self, request): self._set_students_active(True) return Response(status=status.HTTP_200_OK) class ExamApiViewSet(viewsets.ReadOnlyModelViewSet): """ Gets a list of an individual exam by Id if provided """ permission_classes = (IsReviewer,) queryset = ExamType.objects.all() serializer_class = ExamSerializer class TutorApiViewSet( mixins.RetrieveModelMixin, mixins.CreateModelMixin, mixins.DestroyModelMixin, mixins.ListModelMixin, viewsets.GenericViewSet): """ Api endpoint for creating, listing, viewing or deleteing tutors """ permission_classes = (IsReviewer,) queryset = models.UserAccount.objects.filter(role='Tutor') serializer_class = TutorSerializer lookup_field = 'username' lookup_url_kwarg = 'username' class SubmissionTypeApiView(viewsets.ReadOnlyModelViewSet): """ Gets a list or a detail view of a single SubmissionType """ queryset = SubmissionType.objects.all() serializer_class = SubmissionTypeSerializer class StatisticsEndpoint(viewsets.ViewSet): def list(self, request, *args, **kwargs): return Response({ 'submissions_per_type': models.SubmissionType.objects.first().submissions.count(), 'submissions_per_student': models.SubmissionType.objects.count(), 'current_mean_score': models.Feedback.objects.aggregate(avg=Avg('score')).get('avg', 0), 'submission_type_progress': models.SubmissionType.get_annotated_feedback_count().values( 'feedback_count', 'pk', 'percentage', 'name') }) class SubmissionViewSet(viewsets.ReadOnlyModelViewSet): permission_classes = (IsTutorOrReviewer, ) serializer_class = SubmissionNoTypeSerializer def get_queryset(self): if self.request.user.is_reviewer(): return models.Submission.objects.all() else: return models.Submission.objects.filter( assignments__subscription__owner=self.request.user )