import logging from rest_framework import mixins, status, viewsets from rest_framework.response import Response from core import models, permissions, serializers log = logging.getLogger(__name__) class FeedbackApiView( mixins.CreateModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet): """ Gets a list of an individual exam by Id if provided """ permission_classes = (permissions.IsTutorOrReviewer,) queryset = models.Feedback.objects.all() serializer_class = serializers.FeedbackSerializer lookup_field = 'of_submission__pk' lookup_url_kwarg = 'submission_pk' def _tutor_attempts_to_change_final_feedback(self, serializer): feedback_is_final = serializer.instance.is_final user_is_tutor = self.request.user.role == models.UserAccount.TUTOR return feedback_is_final and user_is_tutor def _get_implicit_assignment_for_user(self, submission): return models.TutorSubmissionAssignment.objects.get( subscription__owner=self.request.user, submission=submission ) def _request_user_does_not_own_assignment(self, serializer): try: submission = serializer.validated_data['of_submission'] assignment = self._get_implicit_assignment_for_user(submission) return assignment.subscription.owner != self.request.user except models.TutorSubmissionAssignment.DoesNotExist as err: return True def _tutor_attempts_to_set_first_feedback_final(self, serializer): is_final_set = serializer.validated_data.get('is_final', False) user_is_tutor = self.request.user.role == models.UserAccount.TUTOR return is_final_set and user_is_tutor def _tutor_is_allowed_to_change_own_feedback(self, serializer): submission = self.get_object().of_submission assignment = self._get_implicit_assignment_for_user(submission) youngest = models.TutorSubmissionAssignment.objects \ .filter(submission=submission) \ .order_by('-created') \ .first() return assignment == youngest def _tutor_attempts_to_patch_first_feedback_final(self, serializer): is_final_set = serializer.validated_data.get('is_final', False) submission = self.get_object().of_submission assignment = self._get_implicit_assignment_for_user(submission) in_creation = assignment.subscription.feedback_stage == models.SubmissionSubscription.FEEDBACK_CREATION # noqa return is_final_set and in_creation def create(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) if self._tutor_attempts_to_set_first_feedback_final(serializer): return Response( {'For tutors it is not allowed to create feedback final.'}, status=status.HTTP_403_FORBIDDEN) if self._request_user_does_not_own_assignment(serializer): return Response( {'This user has no permission to create this feedback'}, status=status.HTTP_403_FORBIDDEN) self.perform_create(serializer) return Response(serializer.data, status=status.HTTP_201_CREATED) def partial_update(self, request, **kwargs): feedback = self.get_object() serializer = self.get_serializer(feedback, data=request.data, partial=True) serializer.is_valid(raise_exception=True) if self._tutor_attempts_to_change_final_feedback(serializer): return Response( {"Changing final feedback is not allowed"}, status=status.HTTP_403_FORBIDDEN) if self._tutor_attempts_to_patch_first_feedback_final(serializer): return Response( {'Cannot set the first feedback final unless user reviewer'}, status=status.HTTP_403_FORBIDDEN) if not self._tutor_is_allowed_to_change_own_feedback(serializer): return Response( {'Sorry, but somebody else is already working on this on'}, status=status.HTTP_403_FORBIDDEN) serializer.save() return Response(serializer.data)