wip: assignment resolving experimental

This commit is contained in:
Livio Bieri 2023-10-19 14:56:08 +02:00
parent 232270a506
commit d16bb59392
1 changed files with 280 additions and 0 deletions

View File

@ -0,0 +1,280 @@
from datetime import datetime
from typing import NamedTuple, List
from graphene_django.utils import GraphQLTestCase
from vbv_lernwelt.assignment.models import (
AssignmentType,
AssignmentCompletion,
Assignment,
AssignmentCompletionStatus,
)
from vbv_lernwelt.assignment.tests.assignment_factories import (
AssignmentFactory,
AssignmentListPageFactory,
)
from vbv_lernwelt.course.models import CourseSessionUser, CourseSession
from vbv_lernwelt.course_session.models import (
CourseSessionAssignment,
CourseSessionEdoniqTest,
)
from vbv_lernwelt.dashboard.tests.graphql.utils import (
add_course_session_user,
create_circle,
create_course,
create_course_session,
create_user,
)
from vbv_lernwelt.learnpath.tests.learning_path_factories import (
LearningContentAssignmentFactory,
LearningContentEdoniqTestFactory,
)
from vbv_lernwelt.notify.email.email_services import format_swiss_datetime
class AssignmentCompletionMetrics(NamedTuple):
passed: int
failed: int
unranked: int
@property
def ranking_completed(self) -> bool:
"""
Assumption: Completed means all users have been ranked
(passed or failed) -> intermediate states are irrelevant
for the course session supervisor.
"""
return self.unranked == 0
@property
def average_passed(self) -> float:
total = self.passed + self.failed + self.unranked
if total == 0:
return 0
return self.passed / total
class AssignmentCompletionsStatistics(NamedTuple):
count_completed: int
average_passed: float
def calculate_assignment_completions_statistics(
metrics: List[AssignmentCompletionMetrics],
) -> AssignmentCompletionsStatistics:
completed_metrics = [m for m in metrics if m.ranking_completed]
if not completed_metrics:
return AssignmentCompletionsStatistics(count_completed=0, average_passed=0)
count_completed = len(completed_metrics)
average_passed_completed = (
sum([m.average_passed for m in completed_metrics]) / count_completed
)
return AssignmentCompletionsStatistics(
count_completed=count_completed, average_passed=average_passed_completed
)
def get_assignment_completion_metrics(
course_session: CourseSession, assignment: Assignment
) -> AssignmentCompletionMetrics:
course_session_users = CourseSessionUser.objects.filter(
course_session=course_session,
role=CourseSessionUser.Role.MEMBER,
).values_list("user", flat=True)
evaluation_results = AssignmentCompletion.objects.filter(
completion_status=AssignmentCompletionStatus.EVALUATION_SUBMITTED,
assignment_user__in=course_session_users,
course_session=course_session,
assignment=assignment,
).values_list("evaluation_passed", flat=True)
count_passed = len([passed for passed in evaluation_results if passed])
count_failed = len(evaluation_results) - count_passed
count_unranked = len(course_session_users) - count_passed - count_failed
return AssignmentCompletionMetrics(
passed=count_passed, failed=count_failed, unranked=count_unranked
)
class DashboardAssignmentRecord(NamedTuple):
course_session_id: str
circle_id: str
# type of assignment (translated client-side)
assignment_type_translation_key: str
assignment_title: str
deadline: datetime
metrics: AssignmentCompletionMetrics
details_url: str
@property
def deadline_formatted(self) -> str:
return format_swiss_datetime(self.deadline)
def create_dashboard_record(
course_session_assignment: CourseSessionAssignment | CourseSessionEdoniqTest,
) -> DashboardAssignmentRecord:
if isinstance(course_session_assignment, CourseSessionAssignment):
due_date = course_session_assignment.submission_deadline
else:
due_date = course_session_assignment.deadline
learning_content = course_session_assignment.learning_content
return DashboardAssignmentRecord(
course_session_id=str(course_session_assignment.course_session.id),
circle_id=learning_content.get_circle().id,
assignment_type_translation_key=due_date.assignment_type_translation_key,
assignment_title=learning_content.content_assignment.title,
metrics=get_assignment_completion_metrics(
course_session=course_session_assignment.course_session,
assignment=learning_content.content_assignment,
),
details_url=due_date.url_expert,
deadline=due_date.start,
)
def trybetter(course_session):
dashboard_records: List[DashboardAssignmentRecord] = []
for course_session_assignment in CourseSessionAssignment.objects.filter(
course_session=course_session,
learning_content__assignment_type__in=[
AssignmentType.CASEWORK.value,
AssignmentType.PREP_ASSIGNMENT.value,
],
):
dashboard_record = create_dashboard_record(course_session_assignment)
dashboard_records.append(dashboard_record)
for course_session_edoniq_test in CourseSessionEdoniqTest.objects.filter(
course_session=course_session
):
dashboard_record = create_dashboard_record(course_session_edoniq_test)
dashboard_records.append(dashboard_record)
return sorted(dashboard_records, key=lambda r: r.deadline)
class AssignmentTestCase(GraphQLTestCase):
GRAPHQL_URL = "/server/graphql/"
def test_assignment_something_not_yet_sure_what_exactly_who_knows(self):
# GIVEN
course, course_page = create_course("Test Course")
course_session = create_course_session(course=course, title="Test Bern 2022 a")
circle, _ = create_circle(title="Test Circle", course_page=course_page)
supervisor = create_user("supervisor")
add_course_session_user(
course_session=course_session,
user=supervisor,
role=CourseSessionUser.Role.SESSION_SUPERVISOR,
)
m1 = create_user("member_1")
add_course_session_user(
course_session=course_session,
user=m1,
role=CourseSessionUser.Role.MEMBER,
)
m2 = create_user("member_2")
add_course_session_user(
course_session=course_session,
user=m2,
role=CourseSessionUser.Role.MEMBER,
)
m3 = create_user("member_3")
add_course_session_user(
course_session=course_session,
user=m3,
role=CourseSessionUser.Role.MEMBER,
)
e1 = create_user("expert_1")
add_course_session_user(
course_session=course_session,
user=e1,
role=CourseSessionUser.Role.EXPERT,
)
assignment = AssignmentFactory(
parent=AssignmentListPageFactory(
parent=course.coursepage,
),
assignment_type=AssignmentType.CASEWORK.name,
title="Test Assignment",
effort_required="However long it takes",
intro_text="Assignment Intro Text",
performance_objectives=[],
)
edoniq_test = AssignmentFactory(
parent=AssignmentListPageFactory(
parent=course.coursepage,
),
assignment_type=AssignmentType.EDONIQ_TEST.name,
title="Edoniq Test Assignment",
effort_required="However long it takes",
intro_text="Edoniq Test Assigment Intro Text",
performance_objectives=[],
)
AssignmentCompletion.objects.create(
assignment_user=m1,
assignment=edoniq_test,
evaluation_passed=True,
course_session=course_session,
completion_data={},
)
AssignmentCompletion.objects.create(
assignment_user=m1,
assignment=assignment,
evaluation_passed=True,
course_session=course_session,
completion_data={},
)
learning_content_assignment = LearningContentAssignmentFactory(
title="Learning Content Assignment Title",
parent=circle,
content_assignment=assignment,
)
learning_content_edoniq_test = LearningContentEdoniqTestFactory(
title="Learning Content Edoniq Test Title",
parent=circle,
content_assignment=edoniq_test,
)
CourseSessionAssignment.objects.create(
course_session=course_session, learning_content=learning_content_assignment
)
CourseSessionEdoniqTest.objects.create(
course_session=course_session, learning_content=learning_content_edoniq_test
)
# ---------------------------------------------------------------------
# ---------------------------------------------------------------------
# ---------------------------------------------------------------------
# ---------------------------------------------------------------------
trybetter(course_session)
self.client.force_login(supervisor)