import uuid import structlog from django.shortcuts import get_object_or_404 from rest_framework.decorators import api_view, permission_classes from rest_framework.exceptions import PermissionDenied from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response from vbv_lernwelt.core.models import User from vbv_lernwelt.core.serializers import UserSerializer from vbv_lernwelt.course.models import CourseCompletion, CourseSession from vbv_lernwelt.iam.permissions import can_view_course_completions from vbv_lernwelt.learning_mentor.models import LearningMentor from vbv_lernwelt.learnpath.models import Circle, LearningUnit from vbv_lernwelt.notify.services import NotificationService from vbv_lernwelt.self_evaluation_feedback.models import ( CourseCompletionFeedback, SelfEvaluationFeedback, ) from vbv_lernwelt.self_evaluation_feedback.serializers import ( SelfEvaluationFeedbackSerializer, ) from vbv_lernwelt.self_evaluation_feedback.utils import ( AssessmentCounts, get_self_assessment_counts, get_self_evaluation_feedback_counts, ) logger = structlog.get_logger(__name__) @api_view(["POST"]) @permission_classes([IsAuthenticated]) def start_self_evaluation_feedback(request, learning_unit_id): feedback_provider_user_id = request.data.get("feedback_provider_user_id") learning_unit = get_object_or_404(LearningUnit, id=learning_unit_id) feedback_provider_user = get_object_or_404(User, id=feedback_provider_user_id) if not LearningMentor.objects.filter( course_session__course=learning_unit.get_course(), mentor=feedback_provider_user, participants__user=request.user, ).exists(): raise PermissionDenied() # calling start multiple times shall be a no-op feedback, created = SelfEvaluationFeedback.objects.get_or_create( feedback_requester_user=request.user, feedback_provider_user=feedback_provider_user, learning_unit=learning_unit, ) if created: NotificationService.send_self_evaluation_feedback_request_feedback_notification( self_evaluation_feedback=feedback ) return Response({"success": True}) @api_view(["PUT"]) @permission_classes([IsAuthenticated]) def release_provider_self_evaluation_feedback(request, feedback_id): feedback = get_object_or_404( SelfEvaluationFeedback, id=feedback_id, feedback_provider_user=request.user ) if feedback.feedback_submitted: return Response({"success": True}) feedback.feedback_submitted = True feedback.save() NotificationService.send_self_evaluation_feedback_received_notification( self_evaluation_feedback=feedback ) return Response({"success": True}) @api_view(["GET"]) @permission_classes([IsAuthenticated]) def get_self_evaluation_feedback_as_provider(request, learning_unit_id): feedback = get_object_or_404( SelfEvaluationFeedback, learning_unit_id=learning_unit_id, feedback_provider_user=request.user, ) return Response(SelfEvaluationFeedbackSerializer(feedback).data) @api_view(["GET"]) @permission_classes([IsAuthenticated]) def get_course_session_user_feedback_summaries( request, course_session_id: int, user_id: uuid.UUID ): course_session = get_object_or_404(CourseSession, id=course_session_id) user_to_lookup = get_object_or_404(User, id=user_id) if not can_view_course_completions( user=request.user, # noqa course_session_id=course_session_id, target_user_id=str(user_id), ): raise PermissionDenied() results = [] circle_ids = set() all_self_assessment_counts = [] all_feedback_assessment_counts = [] for learning_unit in LearningUnit.objects.filter( course_category__course=course_session.course, ): # this is not a problem in real life, but in the test environment # we have a lot of learning units without self assessment criteria # -> just skip those learning units if len(learning_unit.performancecriteria_set.all()) == 0: continue circle = learning_unit.get_parent().specific circle_ids.add(circle.id) feedback = SelfEvaluationFeedback.objects.filter( learning_unit=learning_unit, feedback_requester_user=user_to_lookup, ).first() if not feedback: # no feedback given yet feedback_assessment = None else: # feedback given feedback_counts = get_self_evaluation_feedback_counts(feedback) all_feedback_assessment_counts.append(feedback_counts) feedback_assessment = { "submitted_by_provider": feedback.feedback_submitted, "provider_user": UserSerializer(feedback.feedback_provider_user).data, "counts": { "pass": feedback_counts.pass_count, "fail": feedback_counts.fail_count, "unknown": feedback_counts.unknown_count, }, } self_assessment_counts = get_self_assessment_counts( learning_unit=learning_unit, user=user_to_lookup ) all_self_assessment_counts.append(self_assessment_counts) results.append( { "id": learning_unit.id, "title": learning_unit.title, "detail_url": learning_unit.get_evaluate_url(), "circle_id": circle.id, "circle_title": circle.title, "feedback_assessment": feedback_assessment, "self_assessment": { "counts": { "pass": self_assessment_counts.pass_count, "fail": self_assessment_counts.fail_count, "unknown": self_assessment_counts.unknown_count, } }, } ) self_assessment_counts_aggregate = AssessmentCounts( pass_count=sum(x.pass_count for x in all_self_assessment_counts), fail_count=sum(x.fail_count for x in all_self_assessment_counts), unknown_count=sum(x.unknown_count for x in all_self_assessment_counts), ) received_feedback_counts_aggregate = AssessmentCounts( pass_count=sum(x.pass_count for x in all_feedback_assessment_counts), fail_count=sum(x.fail_count for x in all_feedback_assessment_counts), unknown_count=sum(x.unknown_count for x in all_feedback_assessment_counts), ) # pad the feedback counts with unknowns for the # learning units where we have no feedback yet feedback_assessment_counts_aggregate = AssessmentCounts( pass_count=received_feedback_counts_aggregate.pass_count, fail_count=received_feedback_counts_aggregate.fail_count, unknown_count=self_assessment_counts_aggregate.total_count - received_feedback_counts_aggregate.total_count + received_feedback_counts_aggregate.unknown_count, ) return Response( { "results": results, "circles": list( Circle.objects.filter(id__in=circle_ids).values("id", "title") ), "aggregates": { "feedback_assessment": { "pass": feedback_assessment_counts_aggregate.pass_count, "fail": feedback_assessment_counts_aggregate.fail_count, "unknown": feedback_assessment_counts_aggregate.unknown_count, }, "self_assessment": { "pass": self_assessment_counts_aggregate.pass_count, "fail": self_assessment_counts_aggregate.fail_count, "unknown": self_assessment_counts_aggregate.unknown_count, }, }, } ) @api_view(["GET"]) @permission_classes([IsAuthenticated]) def get_self_evaluation_feedback_as_requester(request, learning_unit_id): learning_unit = get_object_or_404(LearningUnit, id=learning_unit_id) feedback = get_object_or_404( SelfEvaluationFeedback, learning_unit=learning_unit, feedback_requester_user=request.user, ) return Response(SelfEvaluationFeedbackSerializer(feedback).data) @api_view(["PUT"]) @permission_classes([IsAuthenticated]) def add_provider_self_evaluation_feedback(request, feedback_id): feedback_assessment = request.data.get("feedback_assessment") feedback = get_object_or_404( SelfEvaluationFeedback, id=feedback_id, feedback_provider_user=request.user ) course_completion = get_object_or_404( CourseCompletion, id=request.data.get("course_completion_id"), user=feedback.feedback_requester_user, ) ( course_completion_feedback, created, ) = CourseCompletionFeedback.objects.get_or_create( feedback=feedback, course_completion=course_completion, defaults={"feedback_assessment": feedback_assessment}, ) if not created: course_completion_feedback.feedback_assessment = feedback_assessment course_completion_feedback.save() return Response({"success": True})