コード例 #1
0
ファイル: tests.py プロジェクト: zznidar/urnik
    def _finalized_exchange_pair_checks(self, exchange_left, exchange_right):
        """Perform common checks for the consistency of two completed exchanges."""
        exchange_left.refresh_from_db()
        exchange_right.refresh_from_db()

        self.assertTrue(exchange_left.is_finalized())
        self.assertTrue(exchange_right.is_finalized())
        self.assertEqual(exchange_left.finalizer_exchange, exchange_right)
        self.assertEqual(exchange_right.finalized_exchange, exchange_left)
        self.assertIsNone(exchange_left.get_match())
        self.assertIsNone(exchange_right.get_match())

        # check if student allocations have been exchanged as requested
        # but only when we actually have student objects available (not for FREE_CHANGE, TEACHER_OFFER)
        if exchange_left.initiator_student is not None:
            self.assertEqual(exchange_right.allocation_from,
                             get_current_student_subject_allocation(self.timetable, exchange_left.initiator_student,
                                                                    Activity.from_timetable_activity(
                                                                        exchange_right.allocation_from.activityRealization.activity).subject,
                                                                    activity_types=["LAB", "LV", "AV"]))

        if exchange_right.initiator_student is not None:
            self.assertEqual(exchange_left.allocation_from,
                             get_current_student_subject_allocation(self.timetable, exchange_right.initiator_student,
                                                                    Activity.from_timetable_activity(
                                                                        exchange_left.allocation_from.activityRealization.activity).subject,
                                                                    activity_types=["LAB", "LV", "AV"]))
コード例 #2
0
ファイル: tests.py プロジェクト: zznidar/urnik
 def test_get_current_student_subject_allocation(self):
     lab = get_current_student_subject_allocation(self.timetable, self.students[0], self.subjects[0],
                                                  activity_types=["LAB", "LV", "AV"])
     lec = get_current_student_subject_allocation(self.timetable, self.students[0], self.subjects[0],
                                                  activity_types=["P"])
     self.assertEqual(self.timetable, lab.timetable)
     self.assertEqual(self.timetable, lec.timetable)
     self.assertEqual(self.subjects[0],
                      Activity.from_timetable_activity(lab.activityRealization.activity).subject)
     self.assertEqual(self.subjects[0],
                      Activity.from_timetable_activity(lec.activityRealization.activity).subject)
コード例 #3
0
ファイル: tests.py プロジェクト: zznidar/urnik
 def test_number_of_students_in_allocation(self):
     num = number_of_students_in_allocation(get_current_student_subject_allocation(self.timetable,
                                                                                   self.students[0],
                                                                                   self.subjects[0],
                                                                                   ["LAB", "LV", "AV"]))
     # change this as needed
     self.assertEqual(20, num)
コード例 #4
0
ファイル: tests.py プロジェクト: zznidar/urnik
 def test_get_allocation_student_group_exists(self):
     # quite a roundabout way, but reliable I guess
     self.assertIsNotNone(get_allocation_student_group(get_current_student_subject_allocation(self.timetable,
                                                                                              self.students[0],
                                                                                              self.subjects[0],
                                                                                              ["LAB", "LV", "AV"]),
                                                       self.students[0]))
コード例 #5
0
def landing_student(request, timetable_slug):
    selected_timetable = get_object_or_404(Timetable, slug=timetable_slug)
    student = Student.from_user(request.user)

    student_exchanges = get_student_exchanges(selected_timetable, student)
    pending_exchanges = [
        ex for ex in student_exchanges if not ex.is_finalized()
    ]
    completed_exchanges = [ex for ex in student_exchanges if ex.is_finalized()]

    student_subjects = get_student_subject_list(selected_timetable, student)
    available_subject_exchanges_allocations = []
    for s in student_subjects:
        # don't show the subject if the student doesn't attend any lab cycles
        try:
            a = get_current_student_subject_allocation(selected_timetable,
                                                       student, s,
                                                       ["LAB", "LV", "AV"])
        except:
            continue
        available_subject_exchanges_allocations.append(
            (s, get_subject_exchanges(selected_timetable, s), a))

    return render(
        request, "exchange/student_main.html", {
            'selected_timetable':
            selected_timetable.__dict__,
            'user':
            request.user.__dict__,
            'student':
            student,
            'pending_exchanges':
            pending_exchanges,
            'completed_exchanges':
            completed_exchanges,
            'available_subject_exchanges_allocations':
            available_subject_exchanges_allocations,
        })
コード例 #6
0
ファイル: tests.py プロジェクト: zznidar/urnik
    def setUpTestData(cls):
        """IMPORTANT: Do not delete any objects, because they are not automatically recovered."""
        super().setUpTestData()

        lv = ["LAB", "LV", "AV"]
        cls.exchanges: List[Exchange] = []

        # ensure datetimes are generated distinctly and logically
        def get_datetime_iterator():
            base_datetime = datetime.utcnow() - timedelta(hours=1)
            iteration = 0
            while True:
                yield base_datetime + timedelta(seconds=iteration)
                iteration += 1
        datetime_iterator = get_datetime_iterator()

        # 0: initiator, by students[0], subjects[0], to students[1]'s allocation
        cls.exchanges.append(Exchange.objects.create(
            allocation_from=get_current_student_subject_allocation(cls.timetable, cls.students[0], cls.subjects[0], lv),
            allocation_to=get_current_student_subject_allocation(cls.timetable, cls.students[1], cls.subjects[0], lv),
            initiator_student=cls.students[0],
            requested_finalizer_student=None,
            date_created=next(datetime_iterator)
        ))

        # 1: finaliser, by students[1], subjects[0], counterpart to 0)
        cls.exchanges.append(Exchange.objects.create(
            allocation_from=get_current_student_subject_allocation(cls.timetable, cls.students[1], cls.subjects[0], lv),
            allocation_to=get_current_student_subject_allocation(cls.timetable, cls.students[0], cls.subjects[0], lv),
            initiator_student=cls.students[1],
            requested_finalizer_student=None,
            date_created=next(datetime_iterator)
        ))

        # 2: initiator, by students[0], subjects[1], has no match (when a correct destination allocation is selected)
        cls.exchanges.append(Exchange.objects.create(
            allocation_from=get_current_student_subject_allocation(cls.timetable, cls.students[0], cls.subjects[1], lv),
            allocation_to=cls._get_student_subject_allocation_inverse(cls.timetable, cls.students[0], cls.subjects[1],
                                                                      lv, skip=2),
            initiator_student=cls.students[0],
            requested_finalizer_student=None,
            date_created=next(datetime_iterator)
        ))

        # 3: initiator, by students[0], subjects[1], different destination lab cycle than 2)
        cls.exchanges.append(Exchange.objects.create(
            allocation_from=get_current_student_subject_allocation(cls.timetable, cls.students[0], cls.subjects[1], lv),
            allocation_to=cls._get_student_subject_allocation_inverse(cls.timetable, cls.students[0], cls.subjects[1],
                                                                      lv, skip=1),
            initiator_student=cls.students[0],
            requested_finalizer_student=None,
            date_created=next(datetime_iterator)
        ))

        # 4: finalizer, by teachers[1], subjects[1], matches above (teacher offer)
        cls.exchanges.append(Exchange.objects.create(
            allocation_from=cls._get_student_subject_allocation_inverse(cls.timetable, cls.students[0], cls.subjects[1],
                                                                        lv, skip=1),
            allocation_to=get_current_student_subject_allocation(cls.timetable, cls.students[0], cls.subjects[1], lv),
            initiator_student=None,
            requested_finalizer_student=cls.students[0],
            date_created=next(datetime_iterator)
        ))

        # 5: initiator, by students[2], subjects[1], same destination than 3), but chronologically after so lower prio
        cls.exchanges.append(Exchange.objects.create(
            allocation_from=get_current_student_subject_allocation(cls.timetable, cls.students[2], cls.subjects[1], lv),
            allocation_to=cls._get_student_subject_allocation_inverse(cls.timetable, cls.students[0], cls.subjects[1],
                                                                      lv, skip=1),
            initiator_student=cls.students[2],
            requested_finalizer_student=None,
            date_created=next(datetime_iterator)
        ))

        # 6: initiator, by students[2], subjects[1], specified students[3], chronologically after 2, 3, 4, 5
        cls.exchanges.append(Exchange.objects.create(
            allocation_from=get_current_student_subject_allocation(cls.timetable, cls.students[2], cls.subjects[1], lv),
            allocation_to=get_current_student_subject_allocation(cls.timetable, cls.students[3], cls.subjects[1], lv),
            initiator_student=cls.students[2],
            requested_finalizer_student=cls.students[3],
            date_created=next(datetime_iterator)
        ))

        # 7: finalizer, by students[3], subjects[1], specified students[2], chronologically after 2, 3, 4, 5, 6
        cls.exchanges.append(Exchange.objects.create(
            allocation_from=get_current_student_subject_allocation(cls.timetable, cls.students[3], cls.subjects[1], lv),
            allocation_to=get_current_student_subject_allocation(cls.timetable, cls.students[2], cls.subjects[1], lv),
            initiator_student=cls.students[3],
            requested_finalizer_student=cls.students[2],
            date_created=next(datetime_iterator)
        ))

        # 8: initiator, free change, subjects[0], same as 0), chronologically before (test priority of student-initiated
        #    exchanges, which override free changes, should never be finalised
        cls.exchanges.append(Exchange.objects.create(
            allocation_from=get_current_student_subject_allocation(cls.timetable, cls.students[0], cls.subjects[0], lv),
            allocation_to=None,
            initiator_student=None,
            requested_finalizer_student=None,
            date_created=cls.exchanges[0].date_created - timedelta(days=1)
        ))

        # 9: initiator, free change, subjects[1], should match 10), does not create an inverse free change (no room)
        cls.exchanges.append(Exchange.objects.create(
            allocation_from=cls._get_student_subject_allocation_inverse(cls.timetable, cls.students[4], cls.subjects[1],
                                                                        lv, skip=0),
            allocation_to=None,
            initiator_student=None,
            requested_finalizer_student=None,
            date_created=next(datetime_iterator)
        ))

        # 10: finalizer, by students[4], subjects[1], matches 9)
        cls.exchanges.append(Exchange.objects.create(
            allocation_from=get_current_student_subject_allocation(cls.timetable, cls.students[4], cls.subjects[1], lv),
            allocation_to=cls._get_student_subject_allocation_inverse(cls.timetable, cls.students[4], cls.subjects[1],
                                                                      lv, skip=0),
            initiator_student=cls.students[4],
            requested_finalizer_student=None,
            date_created=next(datetime_iterator)
        ))

        # 11: initiator, free change, subjects[0], should match 12), from an exchange other than that of students[0]
        #     for this subject (so we don't collide with above), should create an inverse free change
        cls.exchanges.append(Exchange.objects.create(
            allocation_from=cls._get_student_subject_allocation_inverse(cls.timetable, cls.students[0], cls.subjects[0],
                                                                        lv, skip=0),
            allocation_to=None,
            initiator_student=None,
            requested_finalizer_student=None,
            date_created=next(datetime_iterator)
        ))

        # 12: finalizer, by students[1], subjects[0], matches 11), to an exchange other than that of students[0]
        #     for this subject (so we don't collide with above)
        cls.exchanges.append(Exchange.objects.create(
            allocation_from=get_current_student_subject_allocation(cls.timetable, cls.students[1], cls.subjects[0], lv),
            allocation_to=cls._get_student_subject_allocation_inverse(cls.timetable, cls.students[0], cls.subjects[0],
                                                                      lv, skip=0),
            initiator_student=cls.students[1],
            requested_finalizer_student=None,
            date_created=next(datetime_iterator)
        ))

        helper_student_13_14 = Student.objects.filter(groups__in=list(
            get_current_student_subject_allocation(cls.timetable, cls.students[3], cls.subjects[2],
                                                   lv).groups.all())).exclude(id__in=[s.id for s in cls.students]).first()

        # 13: initiator, teacher offer, subjects[2], intentionally does not match 14), to a different student
        #     but one that attends the same allocation as students[3]
        cls.exchanges.append(Exchange.objects.create(
            allocation_from=cls._get_student_subject_allocation_inverse(cls.timetable, helper_student_13_14, cls.subjects[2], lv),
            allocation_to=get_current_student_subject_allocation(cls.timetable, cls.students[3], cls.subjects[2], lv),
            initiator_student=None,
            requested_finalizer_student=helper_student_13_14,
            date_created=next(datetime_iterator)
        ))

        # 14: finalizer, by students[3], subjects[2], does not match 13)
        cls.exchanges.append(Exchange.objects.create(
            allocation_from=get_current_student_subject_allocation(cls.timetable, cls.students[3], cls.subjects[2], lv),
            allocation_to=cls._get_student_subject_allocation_inverse(cls.timetable, helper_student_13_14, cls.subjects[2], lv),
            initiator_student=cls.students[3],
            requested_finalizer_student=None,
            date_created=next(datetime_iterator)
        ))
コード例 #7
0
ファイル: tests.py プロジェクト: zznidar/urnik
 def test_get_allocation_student_group_does_not_exist(self):
     self.assertIsNone(get_allocation_student_group(get_current_student_subject_allocation(self.timetable,
                                                                                           self.students[0],
                                                                                           self.subjects[0],
                                                                                           ["LAB", "LV", "AV"]),
                                                    self.students[4]))
コード例 #8
0
ファイル: tests.py プロジェクト: zznidar/urnik
 def test_get_current_student_subject_allocation_null_subject(self):
     with self.assertRaises(ValueError):
         get_current_student_subject_allocation(self.timetable, self.students[0], None, ["LAB", "LV", "AV"])
コード例 #9
0
def create_exchange_teacher(request, timetable_slug, subject_code):
    selected_timetable = get_object_or_404(Timetable, slug=timetable_slug)
    teacher = request.user.teacher
    subject = get_object_or_404(Subject, code=subject_code)

    if not teacher_teaches_subject(selected_timetable, teacher, subject):
        raise PermissionDenied

    activity_types = ["LAB", "LV", "AV"]

    student_selection_form = StudentSelectionForm(Student.objects,
                                                  data=request.GET)
    if not student_selection_form.is_valid():
        return HttpResponseBadRequest()
    selected_student = student_selection_form.cleaned_data["selected_student"]

    try:
        student_allocation = get_current_student_subject_allocation(
            selected_timetable, selected_student, subject, activity_types)
        available_allocations = get_student_subject_other_allocations(
            selected_timetable, selected_student, subject, activity_types)
    except Allocation.DoesNotExist:
        raise Http404(
            "The student does not attend the subject or no allocations have been found."
        )

    exchange_creation_form = TeacherExchangeCreationForm(
        available_allocations,
        data=request.POST or None,
        initial={
            "timetable": selected_timetable,
            "teacher": teacher,
            "student": selected_student,
            "current_student_allocation": student_allocation
        })

    # first way into this is with a submitted form with a selected student
    if request.method == "GET":
        return render(
            request, "exchange/exchange_create.html", {
                "selected_timetable": selected_timetable,
                "form": exchange_creation_form
            })
    else:
        if exchange_creation_form.is_valid():
            any_fulfilled = process_new_exchange_request(
                exchange_creation_form.cleaned_data["timetable"],
                exchange_creation_form.cleaned_data["teacher"],
                exchange_creation_form.cleaned_data["student"],
                exchange_creation_form.get_subject_transfer_map(),
                # the teacher acts as if they attend the allocation the student wants
                force_allocation_from=exchange_creation_form.
                cleaned_data["requested_student_allocation"])
            if any_fulfilled:
                header = "Exchange fulfilled immediately!"
                message = "The request was fulfilled immediately. Verify the new slot on the timetable.."
            else:
                header = "Request added to the queue."
                message = "The request could not be fulfilled immediately and was placed into the queue for it to " \
                          "be fulfilled in the future."
            return render(
                request, "exchange/exchange_create_result.html", {
                    "selected_timetable": selected_timetable,
                    "header": header,
                    "message": message
                })
            pass
        else:
            return render(
                request, "exchange/exchange_create.html", {
                    "selected_timetable": selected_timetable,
                    "form": exchange_creation_form
                })
コード例 #10
0
def create_exchange_student(request, timetable_slug):
    selected_timetable = get_object_or_404(Timetable, slug=timetable_slug)

    student = Student.from_user(request.user)
    subjects = get_student_subject_list(selected_timetable, student)
    subject_available_allocation_map = {}
    subject_attending_allocation_map = {}
    for subject in subjects:
        activity_types = ["LAB", "LV", "AV"]
        try:
            student_allocation = get_current_student_subject_allocation(
                selected_timetable, student, subject, activity_types)
            allocations = get_student_subject_other_allocations(
                selected_timetable, student, subject, activity_types)
            subject_available_allocation_map[subject] = allocations
            subject_attending_allocation_map[subject] = student_allocation
        except Allocation.DoesNotExist:
            # don't show subjects the student doesn't have attend labs for
            pass

    if request.method == "POST":
        form = ExchangeCreationForm(subject_available_allocation_map,
                                    subject_attending_allocation_map,
                                    data=request.POST)
        if form.is_valid():
            try:
                requested_student_string = form.get_requested_student()
                requested_student = None
                if requested_student_string:
                    requested_student = parse_student_from_ambiguous_identifier(
                        requested_student_string)
                any_fulfilled = process_new_exchange_request(
                    selected_timetable, student, requested_student,
                    form.get_subject_transfers(keep_empty=False))
            except FormProcessingError as e:
                return render(
                    request, "exchange/exchange_create_result.html", {
                        "selected_timetable": selected_timetable,
                        "header": e.header,
                        "message": e.message
                    })
            if any_fulfilled:
                header = "Exchange fulfilled immediately!"
                message = "Your request was fulfilled immediately. Check your new slot on your timetable."
            else:
                header = "Request added to the queue."
                message = "Your request could not be fulfilled immediately and was placed into the queue for it to " \
                          "be fulfilled in the future. Check back at a later date!"
            return render(
                request, "exchange/exchange_create_result.html", {
                    "selected_timetable": selected_timetable,
                    "header": header,
                    "message": message
                })
        # otherwise fall through to rendering the same form, with the data filled out, as is tradition
    else:
        form = ExchangeCreationForm(subject_available_allocation_map,
                                    subject_attending_allocation_map)

    return render(request, "exchange/exchange_create.html", {
        "selected_timetable": selected_timetable,
        "form": form
    })