Example #1
0
    def test_save_and_destroy_lock_reviewsubmission(self):

        os = OriginalSubmission(course=self.course,
                                exercise=self.se,
                                submitter_user=self.s1,
                                text="jadajada")
        os.save()

        rl = ReviewLock(review_exercise=self.re,
                        user=self.s2,
                        original_submission=os)
        rl.save()

        rs = ReviewSubmission(course=self.course,
                              exercise=self.re,
                              submitter_user=self.s2,
                              reviewed_submission=os)

        self.assertEqual(ReviewLock.objects.count(), 1)
        rs.save_and_destroy_lock()
        self.assertEqual(ReviewLock.objects.count(), 0)

        rs2 = ReviewSubmission(course=self.course,
                               exercise=self.re,
                               submitter_user=self.s2,
                               reviewed_submission=os)
        self.assertRaises(OperationalError, rs2.save_and_destroy_lock)

        rs2 = ReviewSubmission(course=self.course,
                               exercise=self.re,
                               submitter_user=self.s3,
                               reviewed_submission=os)
        self.assertRaises(OperationalError, rs2.save_and_destroy_lock)
Example #2
0
    def _post_random(self, ctx):
        rlock_list = self.object.reviewlocks_for(self.request.user)
        rlock = rlock_list.last()

        reviewed_submission = None
        lock_was_expired = False

        if rlock:
            reviewed_submission = rlock.original_submission

        elif not rlock and self.object.reviewlock_expiry_hours != 0:
            # if the expiry time has been set and a user keeps the exercise page
            # visible for a very long time without refreshing, it is possible that
            # whenever the form is actually submitted the original reviewlock has
            # already expired and deleted. in that situation, from the system's POV,
            # the user is making a bogus form submission since no lock is held.
            # if this "race condition" happens, grab the originally reviewed submission's
            # PK from the submitted form.
            #
            # this is not beautiful, but serves the purpose. other implementation
            # possibilities could be to just show an error page but that would waste
            # the peer-reviewing efforts by the student. some sort of verification could
            # also be implemented client-side in JavaScript to show the user a warning or
            # something. this, however, is the easiest solution.
            reviewed_submission = self.object.reviewable_exercise.submissions.get(pk=self.request.POST.get('choice'))
            lock_was_expired = True

        new_review_submission = ReviewSubmission(course=ctx['course'],
                                                 submitter_user=self.request.user,
                                                 exercise=self.object,
                                                 reviewed_submission=reviewed_submission)
        if self.object.use_groups:
            new_review_submission.submitter_group = ctx['my_group']

        if lock_was_expired:
            new_review_submission.save()
        else:
            new_review_submission.save_and_destroy_lock()

        self._save_modelform_answers(self.answer_forms, new_review_submission)

        if self.request.LTI_MODE:
            return _construct_aplus_response(exercise=self.object, user=self.request.user)
        return HttpResponseRedirect(new_review_submission.get_absolute_url())
Example #3
0
    def test_studentCannotSubmitMultipleTimes(self):

        # student cannot submit multiple times SubmissionExercises
        for s in [self.s1, self.s2]:

            self.create_originalsubmission_for(self.SE1, s)

            res = self.get(self.SE1, s)
            self.assertContains(
                res, "You have reached the maximum number of submissions")
            self.assertEqual(res.context_data['disable_form'], True)

            # this will try to post (the form is disabled but the user could use devtools) -> should not succeed
            res = self.post(self.SE1, s, {'text': 'bla'})
            self.assertContains(res, "You cannot submit")
            self.assertEqual(res.context_data['disable_form'], True)

        self.assertEqual(OriginalSubmission.objects.count(), 2)

        # this will create two reviewlocks since both loaded the page
        for s in [self.s1, self.s2]:
            res = self.get(self.RE1, s)
            self.assertContains(
                res, f"text by {self.s1 if s == self.s2 else self.s2}")

        self.assertEqual(ReviewLock.objects.all().count(), 2)

        # after submissions are created, no more reviews can be made
        for s in [self.s1, self.s2]:

            rsub = ReviewSubmission(course=self.course,
                                    exercise=self.RE1,
                                    submitter_user=s,
                                    reviewed_submission=ReviewLock.objects.get(
                                        user=s).original_submission)
            rsub.save_and_destroy_lock()
            res = self.get(self.RE1, s)
            self.assertContains(
                res,
                'You have already submitted your peer-reviews to this exercise.'
            )
Example #4
0
    def test_reviewlocks_created_correctly_for_groups(self):

        groups = [
            StudentGroup.objects.create(
                course=self.course,
                name="g1",
                student_usernames=[self.s1.email, self.s2.email]),
            StudentGroup.objects.create(
                course=self.course,
                name="g2",
                student_usernames=[self.s3.email, self.s4.email]),
            StudentGroup.objects.create(
                course=self.course,
                name="g3",
                student_usernames=[self.s5.email, self.s6.email]),
        ]

        se = SubmissionExercise.objects.get(name='T1 TEXT')
        se.use_groups = True
        se.save()

        # OS for all groups
        for s, g in [(self.s1, groups[0]), (self.s3, groups[1]),
                     (self.s5, groups[2])]:
            self.post(se, s, {'text': f'text by {g.name}'})
        self.assertEqual(OriginalSubmission.objects.count(), 3)

        re = se.review_exercise
        re.use_groups = True
        re.save()

        # g1 -> g2, g2 -> g1
        request = self.factory.get('/courses/prog1/F2018/exercises/r/1/')
        self.kwargs['pk'] = re.pk
        for s, target_name in [(self.s1, 'g2'), (self.s2, 'g2'),
                               (self.s3, 'g1'), (self.s4, 'g1')]:
            request.user = s
            response = ReviewExerciseDetailView.as_view()(request,
                                                          **self.kwargs)
            self.assertContains(response, f"text by {target_name}")

        self.assertEqual(ReviewLock.objects.all().count(), 2)

        # g1 -> review for g2
        rlock = re.reviewlocks_for(self.s1).first()
        rsub = ReviewSubmission(course=self.course,
                                exercise=re,
                                submitter_user=self.s1,
                                submitter_group=groups[0],
                                reviewed_submission=rlock.original_submission)
        rsub.save_and_destroy_lock()

        for s in [self.s1, self.s2]:
            request.user = s
            response = ReviewExerciseDetailView.as_view()(request,
                                                          **self.kwargs)
            self.assertContains(
                response, 'You have already submitted your peer-reviews')
            self.assertEqual(response.context_data['disable_form'], True)

        self.assertEqual(ReviewLock.objects.all().count(), 1)

        # increase sub count that groups can do. g1 -> g3
        re.max_submission_count = 2
        re.save()

        for s, target_name in [(self.s1, 'g3'), (self.s2, 'g3')]:
            request.user = s
            response = ReviewExerciseDetailView.as_view()(request,
                                                          **self.kwargs)
            self.assertContains(response, f"text by {target_name}")
        self.assertEqual(ReviewLock.objects.all().count(), 2)

        # nothing left for g3 to review
        for s in [self.s5, self.s6]:
            request.user = s
            response = ReviewExerciseDetailView.as_view()(request,
                                                          **self.kwargs)
            self.assertContains(response, 'no-submissions-for-peer-review')
            self.assertEqual(response.context_data['disable_form'], True)
        self.assertEqual(ReviewLock.objects.all().count(), 2)

        # increase how many reviews can receive. g3 -> g1 since g1 oldest and 1 review
        re.max_reviews_per_submission = 2
        re.save()

        for s, target_name in [(self.s5, 'g1'), (self.s6, 'g1')]:
            request.user = s
            response = ReviewExerciseDetailView.as_view()(request,
                                                          **self.kwargs)
            self.assertContains(response, f"text by {target_name}")
        self.assertEqual(ReviewLock.objects.all().count(), 3)
Example #5
0
    def test_reviewlocks_created_correctly(self):

        se = SubmissionExercise.objects.get(pk=1)
        for s in self.students:
            OriginalSubmission(course=self.course,
                               submitter_user=s,
                               exercise=se,
                               text=f"text by {s}").save()

        # this will create two reviewlocks since both loaded the page
        re = ReviewExercise.objects.get(reviewable_exercise=se)
        for s in [self.s1, self.s2]:
            request = self.factory.get('/courses/prog1/F2018/exercises/r/1/')
            request.user = s
            self.kwargs['pk'] = re.pk

            response = ReviewExerciseDetailView.as_view()(request,
                                                          **self.kwargs)
            self.assertContains(
                response, f"text by {self.s1 if s == self.s2 else self.s2}")

        self.assertEqual(ReviewLock.objects.all().count(), 2)

        # the same reviewlocks are still used since no reviews have been made
        for s in [self.s1, self.s2]:
            request = self.factory.get('/courses/prog1/F2018/exercises/r/1/')
            request.user = s
            self.kwargs['pk'] = re.pk

            response = ReviewExerciseDetailView.as_view()(request,
                                                          **self.kwargs)
            self.assertContains(
                response, f"text by {self.s1 if s == self.s2 else self.s2}")

        self.assertEqual(ReviewLock.objects.all().count(), 2)

        # after submissions are created, no more reviews can be made
        for s in [self.s1, self.s2]:
            rlock = ReviewLock.objects.get(user=s)

            rsub = ReviewSubmission(
                course=self.course,
                exercise=re,
                submitter_user=s,
                reviewed_submission=rlock.original_submission)
            rsub.save_and_destroy_lock()

            request = self.factory.get('/courses/prog1/F2018/exercises/r/1/')
            request.user = s
            self.kwargs['pk'] = re.pk
            response = ReviewExerciseDetailView.as_view()(request,
                                                          **self.kwargs)
            self.assertContains(
                response,
                'You have already submitted your peer-reviews to this exercise.'
            )

        self.assertEqual(ReviewLock.objects.all().count(), 0)
        # now in the system: 4 OS, 0 RL, 2 RS

        # s4 loads the page -> RL should be for s3
        request = self.factory.get('/courses/prog1/F2018/exercises/r/1/')
        request.user = self.s4
        self.kwargs['pk'] = re.pk
        response = ReviewExerciseDetailView.as_view()(request, **self.kwargs)
        self.assertContains(response, f"text by {self.s3}")
        self.assertEqual(ReviewLock.objects.all().count(), 1)

        re.max_submission_count = 2
        re.save()

        # s1 loads the page -> RL should be for s4 since no RLs for s4 exist yet
        request.user = self.s1
        response = ReviewExerciseDetailView.as_view()(request, **self.kwargs)
        self.assertContains(response, f"text by {self.s4}")
        self.assertEqual(ReviewLock.objects.all().count(), 2)

        # s2 loads the page -> nothing to review since all can recieve only one
        request.user = self.s2
        response = ReviewExerciseDetailView.as_view()(request, **self.kwargs)
        self.assertContains(response, f"no-submissions-for-peer-review")
        self.assertEqual(ReviewLock.objects.all().count(), 2)

        # increase the number of reviews an OS can get
        re.max_reviews_per_submission = 2
        re.save()

        # s2 should now get s3 since cannot get himself and s1 already done
        request.user = self.s2
        self.kwargs['pk'] = re.pk
        response = ReviewExerciseDetailView.as_view()(request, **self.kwargs)
        self.assertContains(response, f"text by {self.s3}")
        self.assertEqual(ReviewLock.objects.all().count(), 3)

        # s3 has not yet loaded the page -> should get s1
        request.user = self.s3
        self.kwargs['pk'] = re.pk
        response = ReviewExerciseDetailView.as_view()(request, **self.kwargs)
        self.assertContains(response, f"text by {self.s1}")
        self.assertEqual(ReviewLock.objects.all().count(), 4)