from datetime import datetime, timedelta from typing import List, Tuple from django.contrib.auth.hashers import make_password from django.utils import timezone from vbv_lernwelt.assignment.models import ( Assignment, AssignmentCompletion, AssignmentCompletionStatus, AssignmentType, ) from vbv_lernwelt.assignment.tests.assignment_factories import ( AssignmentFactory, AssignmentListPageFactory, ) from vbv_lernwelt.competence.factories import ( ActionCompetenceFactory, ActionCompetenceListPageFactory, CompetenceCertificateFactory, CompetenceCertificateListFactory, CompetenceNaviPageFactory, PerformanceCriteriaFactory, ) from vbv_lernwelt.competence.models import CompetenceCertificate, PerformanceCriteria from vbv_lernwelt.core.models import User from vbv_lernwelt.course.consts import COURSE_TEST_ID, UK_COURSE_IDS, VV_COURSE_IDS from vbv_lernwelt.course.factories import CoursePageFactory from vbv_lernwelt.course.models import ( Course, CourseCategory, CoursePage, CourseSession, CourseSessionUser, ) from vbv_lernwelt.course.utils import get_wagtail_default_site from vbv_lernwelt.course_session.models import ( CourseSessionAssignment, CourseSessionAttendanceCourse, CourseSessionEdoniqTest, ) from vbv_lernwelt.course_session_group.models import CourseSessionGroup from vbv_lernwelt.duedate.models import DueDate from vbv_lernwelt.learning_mentor.models import LearningMentor from vbv_lernwelt.learnpath.models import ( Circle, LearningContentAssignment, LearningContentEdoniqTest, LearningPath, LearningUnit, ) from vbv_lernwelt.learnpath.tests.learning_path_factories import ( CircleFactory, LearningContentAssignmentFactory, LearningContentAttendanceCourseFactory, LearningContentEdoniqTestFactory, LearningPathFactory, LearningUnitFactory, TopicFactory, ) def create_course( title: str = "Course Title", _id=None, course_page_title: str = "Test Lehrgang" ) -> Tuple[Course, CoursePage]: course = Course.objects.create(id=_id, title=title, category_name="Handlungsfeld") course_page = CoursePageFactory( title=course_page_title, parent=get_wagtail_default_site().root_page, course=course, ) course.slug = course_page.slug course.save() return course, course_page def create_user(username: str) -> User: return User.objects.create_user( username=username, password=make_password("test"), email=f"{username}@example.com", language="de", first_name="Test", last_name=username.capitalize(), ) def create_course_session( course: Course, title: str, generation: str = "2023", _id=None ) -> CourseSession: return CourseSession.objects.create( id=_id, course=course, title=title, import_id=title, generation=generation, start_date=timezone.now(), ) def add_learning_mentor( course_session: CourseSession, mentor: User, mentee: CourseSessionUser ) -> LearningMentor: learning_mentor = LearningMentor.objects.create( course_session=course_session, mentor=mentor ) learning_mentor.participants.add(mentee) return learning_mentor def add_course_session_user( course_session: CourseSession, user: User, role: CourseSessionUser.Role ) -> CourseSessionUser: return CourseSessionUser.objects.create( course_session=course_session, user=user, role=role, ) def create_course_session_group(course_session: CourseSession) -> CourseSessionGroup: group = CourseSessionGroup.objects.create( course=course_session.course, ) group.course_session.add(course_session) return group def add_course_session_group_supervisor(group: CourseSessionGroup, user: User): group.supervisor.add(user) def add_course_session_group_course_session( group: CourseSessionGroup, course_session: CourseSession ): group.course_session.add(course_session) def create_circle( title: str, course_page: CoursePage, learning_path: LearningPath | None = None ) -> Tuple[Circle, LearningPath]: if not learning_path: learning_path = LearningPathFactory(title="Test Lernpfad", parent=course_page) TopicFactory(title="Circle Test Topic", is_visible=False, parent=learning_path) circle = CircleFactory( title=title, parent=learning_path, description="Circle Description" ) return circle, learning_path def create_attendance_course( course_session: CourseSession, circle: Circle, attendance_user_list: List, due_date_end: datetime, ) -> CourseSessionAttendanceCourse: learning_content_dummy = LearningContentAttendanceCourseFactory( title="Lerninhalt Dummy", parent=circle, ) return CourseSessionAttendanceCourse.objects.create( course_session=course_session, learning_content=learning_content_dummy, attendance_user_list=attendance_user_list, due_date=DueDate.objects.create( course_session=course_session, start=due_date_end - timedelta(hours=8), end=due_date_end, ), ) def create_competence_certificate(course: Course) -> CompetenceCertificate: navi = CompetenceNaviPageFactory(parent=course.coursepage) certificate_list = CompetenceCertificateListFactory(parent=navi) return CompetenceCertificateFactory(parent=certificate_list) def create_assignment( course: Course, assignment_type: AssignmentType, ) -> Assignment: return AssignmentFactory( parent=AssignmentListPageFactory( parent=course.coursepage, ), assignment_type=assignment_type.name, title=f"Dummy Assignment ({assignment_type.name})", effort_required=":)", intro_text=":)", performance_objectives=[], ) def create_assignment_completion( user: User, assignment: Assignment, course_session: CourseSession, has_passed: bool | None = None, max_points: int = 0, achieved_points: int = 0, status: AssignmentCompletionStatus = AssignmentCompletionStatus.EVALUATION_SUBMITTED, ) -> AssignmentCompletion: return AssignmentCompletion.objects.create( completion_status=status.value, assignment_user=user, assignment=assignment, evaluation_passed=has_passed, course_session=course_session, completion_data={}, evaluation_max_points=max_points, evaluation_points=achieved_points, ) def create_assignment_learning_content( circle: Circle, assignment: Assignment, ) -> LearningContentAssignment | LearningContentEdoniqTest: if AssignmentType(assignment.assignment_type) == AssignmentType.EDONIQ_TEST: return LearningContentEdoniqTestFactory( title="Learning Content (EDONIQ_TEST)", parent=circle, content_assignment=assignment, ) return LearningContentAssignmentFactory( title=f"Learning Content ({assignment.assignment_type})", parent=circle, content_assignment=assignment, ) def create_course_session_assignment( course_session: CourseSession, learning_content_assignment: LearningContentAssignment, deadline_at: datetime | None = None, ) -> CourseSessionAssignment: cas = CourseSessionAssignment.objects.create( course_session=course_session, learning_content=learning_content_assignment, ) if deadline_at: # the save on the course_session_assignment already sets a lot # of due date fields, so it's easier to just overwrite the this cas.submission_deadline.start = timezone.make_aware(deadline_at) cas.submission_deadline.save() return cas def create_course_session_edoniq_test( course_session: CourseSession, learning_content_edoniq_test: LearningContentEdoniqTest, deadline_at: datetime, ) -> CourseSessionEdoniqTest: cset = CourseSessionEdoniqTest.objects.create( course_session=course_session, learning_content=learning_content_edoniq_test, ) # same as above (see create_course_session_assignment) cset.deadline.start = timezone.make_aware(deadline_at) cset.deadline.save() return cset def create_learning_unit( circle: Circle, course: Course, course_category_title: str = "Course Category", ) -> LearningUnit: cat, _ = CourseCategory.objects.get_or_create( course=course, title=course_category_title, ) return LearningUnitFactory( title="Learning Unit", parent=circle, course_category=cat, ) def create_performance_criteria_page( course: Course, course_page: CoursePage, circle: Circle, learning_unit: LearningUnitFactory | LearningUnit | None = None, ) -> PerformanceCriteria: competence_navi_page = CompetenceNaviPageFactory( title="Competence Navi", parent=course_page, ) competence_profile_page = ActionCompetenceListPageFactory( title="Action Competence Page", parent=competence_navi_page, ) action_competence = ActionCompetenceFactory( parent=competence_profile_page, competence_id="X1", title="Action Competence", items=[("item", "Action Competence Item")], ) if not learning_unit: learning_unit = create_learning_unit(circle=circle, course=course) return PerformanceCriteriaFactory( parent=action_competence, competence_id="X1.1", title="Performance Criteria", learning_unit=learning_unit, ) def create_circle_expert( course_session: CourseSession, circle: Circle, username: str ) -> CourseSessionUser: expert_user = create_user(username) course_session_expert_user = add_course_session_user( course_session=course_session, user=expert_user, role=CourseSessionUser.Role.EXPERT, ) course_session_expert_user.expert.add(circle) return course_session_expert_user def apply_course_configuration(course: Course): """ Apply course configuration based on course id: By default everything is enabled, disable unnecessary features """ if course.id == COURSE_TEST_ID: pass # all features are enabled elif course.id in VV_COURSE_IDS: course.configuration.enable_competence_certificates = False elif course.id in UK_COURSE_IDS: course.configuration.enable_learning_mentor = False else: raise ValueError(f"Unknown course id {course.id}") course.configuration.save() def create_course_with_categories( course_id, title, apps=None, ): if apps is not None: Course = apps.get_model("course", "Course") CourseCategory = apps.get_model("course", "CourseCategory") else: # pylint: disable=import-outside-toplevel from vbv_lernwelt.course.models import Course, CourseCategory course, _ = Course.objects.get_or_create( id=course_id, title=title, category_name="Handlungsfeld", ) apply_course_configuration(course) CourseCategory.objects.get_or_create(course=course, title="Allgemein", general=True) for cat in [ "Fahrzeug", "Reisen", "Einkommenssicherung", "Gesundheit", "Haushalt", "Sparen", "Pensionierung", "KMU", "Wohneigentum", "Rechtsstreitigkeiten", "Erben / Vererben", "Selbstständigkeit", ]: CourseCategory.objects.get_or_create(course=course, title=cat) course_page = CoursePageFactory( title=title, parent=get_wagtail_default_site().root_page, course=course, ) course.slug = course_page.slug course.save() return course