from typing import Type from vbv_lernwelt.assignment.models import ( Assignment, AssignmentCompletion, AssignmentCompletionStatus, ) from vbv_lernwelt.core.models import User from vbv_lernwelt.core.utils import find_first from vbv_lernwelt.course.models import CourseSession def update_assignment_completion( user: User, assignment: Assignment, course_session: CourseSession, completion_data=None, completion_status: Type[AssignmentCompletionStatus] = "in_progress", copy_task_data: bool = False, ) -> AssignmentCompletion: """ :param completion_data: should have the following structure: { "": {"user_data": {"text": "some text from user"}}, "": {"user_data": {"confirmation": true}}, } every input field has the data stored in sub dict of the question uuid it can also contain "trainer_input" when the trainer has entered grading data { "": { "trainer_data": {"points": 4, "text": "Gute Antwort"} }, } :param copy_task_data: if true, the task data will be copied to the completion data used for "submitted" and "graded" status, so that we don't lose the question context :return: AssignmentCompletion """ if completion_data is None: completion_data = {} ac, created = AssignmentCompletion.objects.get_or_create( user_id=user.id, assignment_id=assignment.id, course_session_id=course_session.id, ) ac.completion_status = completion_status # TODO: make more validation of the provided input -> maybe with graphql completion_data = _remove_unknown_entries(assignment, completion_data) for key, value in completion_data.items(): # retain already stored data stored_entry = ac.completion_data.get(key, {}) stored_entry.update(value) ac.completion_data[key] = stored_entry if copy_task_data: # copy over the question data, so that we don't lose the context substasks = assignment.filter_user_subtasks() for key, value in ac.completion_data.items(): task_data = find_first(substasks, pred=lambda x: x["id"] == key) ac.completion_data[key].update(task_data) ac.save() return ac def _remove_unknown_entries(assignment, completion_data): """ Removes all entries from completion_data which are not known to the assignment """ possible_subtask_uuids = [ subtask["id"] for subtask in assignment.filter_user_subtasks() ] filtered_completion_data = { key: value for key, value in completion_data.items() if key in possible_subtask_uuids } return filtered_completion_data