feat: praxis assignments API

This commit is contained in:
Reto Aebersold 2023-12-07 11:19:56 +01:00
parent 56ecb72751
commit a48ac35e62
7 changed files with 240 additions and 138 deletions

View File

@ -0,0 +1,115 @@
from typing import List
from vbv_lernwelt.assignment.models import (
Assignment,
AssignmentCompletion,
AssignmentCompletionStatus,
AssignmentType,
)
from vbv_lernwelt.core.models import User
from vbv_lernwelt.course.models import CourseSession
from vbv_lernwelt.course_session.models import CourseSessionAssignment
from vbv_lernwelt.learning_mentor.entities import (
CompletionStatus,
PraxisAssignmentCompletion,
PraxisAssignmentStatus,
)
def get_assignment_completions(
course_session: CourseSession, assignment: Assignment, participants: List[User]
) -> List[PraxisAssignmentCompletion]:
evaluation_results = AssignmentCompletion.objects.filter(
assignment_user__in=participants,
course_session=course_session,
assignment=assignment,
).values("completion_status", "assignment_user__last_name", "assignment_user")
user_status_map = {}
for result in evaluation_results:
completion_status = result["completion_status"]
if completion_status == AssignmentCompletionStatus.EVALUATION_SUBMITTED.value:
status = CompletionStatus.EVALUATED
elif completion_status in [
AssignmentCompletionStatus.SUBMITTED.value,
AssignmentCompletionStatus.EVALUATION_IN_PROGRESS.value,
]:
status = CompletionStatus.SUBMITTED
else:
status = CompletionStatus.UNKNOWN
user_status_map[result["assignment_user"]] = (
status,
result["assignment_user__last_name"],
)
status_priority = {
CompletionStatus.SUBMITTED: 1,
CompletionStatus.EVALUATED: 2,
CompletionStatus.UNKNOWN: 3,
}
sorted_participants = sorted(
participants,
key=lambda u: (
status_priority.get(
user_status_map.get(u.id, (CompletionStatus.UNKNOWN, ""))[0]
),
user_status_map.get(u.id, ("", u.last_name))[1],
),
)
return [
PraxisAssignmentCompletion(
status=user_status_map.get(
user.id, (CompletionStatus.UNKNOWN, user.last_name)
)[0],
user_id=user.id,
last_name=user.last_name,
)
for user in sorted_participants
]
def get_praxis_assignments(
course_session: CourseSession, participants: List[User]
) -> List[PraxisAssignmentStatus]:
records = []
if not participants:
return records
for course_session_assignment in CourseSessionAssignment.objects.filter(
course_session=course_session,
learning_content__content_assignment__assignment_type__in=[
AssignmentType.PRAXIS_ASSIGNMENT.value,
],
):
learning_content = course_session_assignment.learning_content
completions = get_assignment_completions(
course_session=course_session,
assignment=learning_content.content_assignment,
participants=participants,
)
submitted_count = len(
[
completion
for completion in completions
if completion.status == CompletionStatus.SUBMITTED
]
)
records.append(
PraxisAssignmentStatus(
id=course_session_assignment.id,
title=learning_content.content_assignment.title,
circle_id=learning_content.get_circle().id,
pending_evaluations=submitted_count,
completions=completions,
)
)
return records

View File

@ -0,0 +1,25 @@
from dataclasses import dataclass
from enum import Enum
from typing import List
class CompletionStatus(str, Enum):
UNKNOWN = "UNKNOWN"
SUBMITTED = "SUBMITTED"
EVALUATED = "EVALUATED"
@dataclass
class PraxisAssignmentCompletion:
status: CompletionStatus
user_id: str
last_name: str
@dataclass
class PraxisAssignmentStatus:
id: str
title: str
circle_id: str
pending_evaluations: int
completions: List[PraxisAssignmentCompletion]

View File

@ -0,0 +1,19 @@
from rest_framework import serializers
class PraxisAssignmentCompletionSerializer(serializers.Serializer):
status = serializers.SerializerMethodField()
user_id = serializers.CharField()
last_name = serializers.CharField()
@staticmethod
def get_status(obj):
return obj.status.value
class PraxisAssignmentStatusSerializer(serializers.Serializer):
id = serializers.CharField()
title = serializers.CharField()
circle_id = serializers.CharField()
pending_evaluations = serializers.IntegerField()
completions = PraxisAssignmentCompletionSerializer(many=True)

View File

@ -2,10 +2,19 @@ from django.urls import reverse
from rest_framework import status
from rest_framework.test import APITestCase
from vbv_lernwelt.assignment.models import (
AssignmentCompletion,
AssignmentCompletionStatus,
AssignmentType,
)
from vbv_lernwelt.course.creators.test_utils import (
add_course_session_user,
create_assignment,
create_assignment_learning_content,
create_circle,
create_course,
create_course_session,
create_course_session_assignment,
create_user,
)
from vbv_lernwelt.course.models import CourseSessionUser
@ -14,8 +23,20 @@ from vbv_lernwelt.learning_mentor.models import LearningMentor
class LearningMentorAPITest(APITestCase):
def setUp(self) -> None:
course, course_page = create_course("Test Course")
self.course_session = create_course_session(course=course, title="Test VV")
self.course, self.course_page = create_course("Test Course")
self.course_session = create_course_session(course=self.course, title="Test VV")
circle, _ = create_circle(title="Circle", course_page=self.course_page)
self.assignment = create_assignment(
course=self.course, assignment_type=AssignmentType.PRAXIS_ASSIGNMENT
)
lca = create_assignment_learning_content(circle, self.assignment)
create_course_session_assignment(
course_session=self.course_session, learning_content_assignment=lca
)
self.mentor = create_user("mentor")
self.participant_1 = add_course_session_user(
self.course_session,
@ -87,3 +108,48 @@ class LearningMentorAPITest(APITestCase):
self.assertEqual(participant_1["email"], "participant_1@example.com")
self.assertEqual(participant_1["first_name"], "Test")
self.assertEqual(participant_1["last_name"], "Participant_1")
def test_api_praxis_assignments(self) -> None:
# GIVEN
participants = [self.participant_1, self.participant_2, self.participant_3]
self.client.force_login(self.mentor)
mentor = LearningMentor.objects.create(
mentor=self.mentor,
course=self.course_session.course,
)
mentor.participants.set(participants)
AssignmentCompletion.objects.create(
assignment_user=self.participant_1.user,
course_session=self.course_session,
assignment=self.assignment,
completion_status=AssignmentCompletionStatus.EVALUATION_SUBMITTED.value,
)
AssignmentCompletion.objects.create(
assignment_user=self.participant_3.user,
course_session=self.course_session,
assignment=self.assignment,
completion_status=AssignmentCompletionStatus.SUBMITTED.value,
)
# WHEN
response = self.client.get(self.url)
# THEN
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(response.data["praxis_assignments"]), 1)
assignment = response.data["praxis_assignments"][0]
self.assertEqual(assignment["pending_evaluations"], 1)
self.assertEqual(
assignment["completions"][0]["last_name"], self.participant_3.user.last_name
)
self.assertEqual(
assignment["completions"][1]["last_name"], self.participant_1.user.last_name
)
self.assertEqual(
assignment["completions"][2]["last_name"], self.participant_2.user.last_name
)

View File

@ -14,11 +14,11 @@ from vbv_lernwelt.course.creators.test_utils import (
create_course_session_assignment,
create_user,
)
from vbv_lernwelt.learning_mentor.views import (
CompletionStatus,
from vbv_lernwelt.learning_mentor.content.praxis_assignment import (
get_assignment_completions,
get_praxis_assignments,
)
from vbv_lernwelt.learning_mentor.entities import CompletionStatus
class AttendanceServicesTestCase(TestCase):

View File

@ -1,140 +1,14 @@
from dataclasses import dataclass
from enum import Enum
from typing import List
from rest_framework.decorators import api_view
from rest_framework.generics import get_object_or_404
from rest_framework.response import Response
from vbv_lernwelt.assignment.models import (
Assignment,
AssignmentCompletion,
AssignmentCompletionStatus,
AssignmentType,
)
from vbv_lernwelt.core.models import User
from vbv_lernwelt.core.serializers import UserSerializer
from vbv_lernwelt.course.models import CourseSession
from vbv_lernwelt.course_session.models import CourseSessionAssignment
from vbv_lernwelt.learning_mentor.content.praxis_assignment import (
get_praxis_assignments,
)
from vbv_lernwelt.learning_mentor.models import LearningMentor
class CompletionStatus(str, Enum):
UNKNOWN = "UNKNOWN"
SUBMITTED = "SUBMITTED"
EVALUATED = "EVALUATED"
@dataclass
class PraxisAssignmentCompletion:
status: CompletionStatus
user_id: str
last_name: str
@dataclass
class PraxisAssignmentStatus:
id: str
title: str
circle_id: str
pending_evaluations: int
completions: List[PraxisAssignmentCompletion]
def get_assignment_completions(
course_session: CourseSession, assignment: Assignment, participants: List[User]
) -> List[PraxisAssignmentCompletion]:
evaluation_results = AssignmentCompletion.objects.filter(
assignment_user__in=participants,
course_session=course_session,
assignment=assignment,
).values("completion_status", "assignment_user__last_name", "assignment_user")
user_status_map = {}
for result in evaluation_results:
completion_status = result["completion_status"]
if completion_status == AssignmentCompletionStatus.EVALUATION_SUBMITTED.value:
status = CompletionStatus.EVALUATED
elif completion_status in [
AssignmentCompletionStatus.SUBMITTED.value,
AssignmentCompletionStatus.EVALUATION_IN_PROGRESS.value,
]:
status = CompletionStatus.SUBMITTED
else:
status = CompletionStatus.UNKNOWN
user_status_map[result["assignment_user"]] = (
status,
result["assignment_user__last_name"],
)
status_priority = {
CompletionStatus.SUBMITTED: 1,
CompletionStatus.EVALUATED: 2,
CompletionStatus.UNKNOWN: 3,
}
sorted_participants = sorted(
participants,
key=lambda u: (
status_priority.get(
user_status_map.get(u.id, (CompletionStatus.UNKNOWN, ""))[0]
),
user_status_map.get(u.id, ("", u.last_name))[1],
),
)
return [
PraxisAssignmentCompletion(
status=user_status_map.get(
user.id, (CompletionStatus.UNKNOWN, user.last_name)
)[0],
user_id=user.id,
last_name=user.last_name,
)
for user in sorted_participants
]
def get_praxis_assignments(
course_session: CourseSession, participants: List[User]
) -> List[PraxisAssignmentStatus]:
records = []
for course_session_assignment in CourseSessionAssignment.objects.filter(
course_session=course_session,
learning_content__content_assignment__assignment_type__in=[
AssignmentType.PRAXIS_ASSIGNMENT.value,
],
):
learning_content = course_session_assignment.learning_content
completions = get_assignment_completions(
course_session=course_session,
assignment=learning_content.content_assignment,
participants=participants,
)
submitted_count = len(
[
completion
for completion in completions
if completion.status == CompletionStatus.SUBMITTED
]
)
records.append(
PraxisAssignmentStatus(
id=course_session_assignment.id,
title=learning_content.content_assignment.title,
circle_id=learning_content.get_circle().id,
pending_evaluations=submitted_count,
completions=completions,
)
)
return records
from vbv_lernwelt.learning_mentor.serializers import PraxisAssignmentStatusSerializer
@api_view(["GET"])
@ -150,12 +24,15 @@ def mentor_summary(request, course_session_id: int):
)
participants = mentor.participants.filter(course_session=course_session)
users = [p.user for p in participants]
praxis_assignments = get_praxis_assignments(course_session, users)
return Response(
{
"participants": [UserSerializer(p.user).data for p in participants],
"praxis_assignments": get_praxis_assignments(
course_session, participants
),
"participants": [UserSerializer(user).data for user in users],
"praxis_assignments": PraxisAssignmentStatusSerializer(
praxis_assignments, many=True
).data,
}
)