wip: assignment resolving experimental
This commit is contained in:
parent
232270a506
commit
d16bb59392
|
|
@ -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)
|
||||
Loading…
Reference in New Issue