示例#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)
示例#2
0
    def test_teacherCanSubmitMultipleTimes(self):

        exercise = SubmissionExercise.objects.get(pk=1)
        OriginalSubmission(course=self.course,
                           submitter_user=self.t1,
                           exercise=exercise,
                           text="jadajada").save()
        OriginalSubmission(course=self.course,
                           submitter_user=self.t1,
                           exercise=exercise,
                           text="jadajada").save()
        OriginalSubmission(course=self.course,
                           submitter_user=self.t1,
                           exercise=exercise,
                           text="jadajada").save()

        request = self.factory.get('/courses/prog1/F2018/exercises/s/1/')
        request.user = self.t1
        self.kwargs['pk'] = 1

        response = SubmissionExerciseDetailView.as_view()(request,
                                                          **self.kwargs)

        self.assertNotContains(
            response, "You have reached the maximum number of submissions")
        self.assertContains(response, "Submit")
示例#3
0
    def test_student_can_download_submission(self):
        exercise = SubmissionExercise.objects.get(pk=1)

        group = StudentGroup(name="g-1",
                             student_usernames=[self.s1.email, self.s2.email],
                             course=self.course)
        group.save()

        exercise.type = 'FILE_UPLOAD'
        exercise.accepted_filetypes = '.txt'
        exercise.save()

        temp_file = SimpleUploadedFile(name='lorem_ipsum.txt',
                                       content=bytearray('jada jada', 'utf-8'))
        sub = OriginalSubmission(course=self.course,
                                 file=temp_file,
                                 submitter_user=self.s1,
                                 submitter_group=group,
                                 exercise=exercise)
        sub.save()

        for user, code in [(self.s1, 200), (self.s2, 200), (self.s3, 403)]:
            request = self.factory.get(
                f'/courses/prog1/F2018/submissions/download/{sub.pk}/')
            request.user = user
            self.kwargs['pk'] = sub.pk

            if code == 403:
                self.assertRaises(PermissionDenied,
                                  DownloadSubmissionView.as_view(), request,
                                  **self.kwargs)
            else:
                response = DownloadSubmissionView.as_view()(request,
                                                            **self.kwargs)
                self.assertEqual(response.status_code, code)
示例#4
0
文件: core.py 项目: piehei/prplatform
def create_submission_for(submission_exercise, aplus_submission, user):
    """
       1. check if there's an user with the aplus submitter's email
       2. if not, crate one and set temporary = True
       3. get the submissions file from aplus API
       4. create a new original submission with the file and submitter
    """

    file_url = aplus_submission["files"][0]["url"]
    filename = aplus_submission["files"][0]["filename"]
    file_blob = requests.get(file_url, headers={ 'Authorization': f'Token {submission_exercise.course.aplus_apikey}' })

    temp_file = NamedTemporaryFile(delete=True)
    temp_file.name = filename
    temp_file.write(file_blob.content)
    temp_file.flush()

    new_orig_sub = OriginalSubmission(
                        course=submission_exercise.course,
                        submitter_user=user,
                        exercise=submission_exercise,
                        file=File(temp_file)
                        )
    new_orig_sub.save()
    logger.info(new_orig_sub)
示例#5
0
    def create_submission_for(self, exercise, users):

        submissions = []
        for user in users:
            sub = OriginalSubmission(course=self.course,
                                     submitter_user=user,
                                     exercise=exercise,
                                     text=f"text by {user}")
            sub.save()
            submissions.append(sub)
        return submissions
示例#6
0
    def create_originalsubmission_for(self, exercise, users):
        if type(users) is not list:
            users = [users]

        submissions = []
        for user in users:
            sub = OriginalSubmission(course=self.course,
                                     submitter_user=user,
                                     exercise=exercise,
                                     text=f"text by {user}")
            sub.save()
            submissions.append(sub)
        return submissions if len(submissions) > 1 else submissions[0]
示例#7
0
    def test_student_can_download_via_reviewlock(self):
        exercise = SubmissionExercise.objects.get(pk=1)

        exercise.type = 'FILE_UPLOAD'
        exercise.accepted_filetypes = '.txt'
        exercise.save()

        temp_file = SimpleUploadedFile(name='lorem_ipsum.txt',
                                       content=bytearray('jada jada', 'utf-8'))
        sub = OriginalSubmission(course=self.course,
                                 file=temp_file,
                                 submitter_user=self.s1,
                                 exercise=exercise)
        sub.save()

        re = ReviewExercise.objects.get(pk=1)
        re.type = ReviewExercise.RANDOM
        re.save()

        rlock = ReviewLock(user=self.s2,
                           original_submission=sub,
                           review_exercise=re,
                           review_submission=None)
        rlock.save()

        # user with reviewlock can download
        request = self.factory.get(
            f'/courses/prog1/F2018/submissions/download/{sub.pk}/')
        request.user = self.s2
        self.kwargs['pk'] = sub.pk
        response = DownloadSubmissionView.as_view()(request, **self.kwargs)
        self.assertEqual(response.status_code, 200)

        re.use_groups = True
        re.save()
        group = StudentGroup(name="g-1",
                             student_usernames=[self.s2.email, self.s3.email],
                             course=self.course)
        group.save()
        rlock.group = group
        rlock.save()

        # user in a group that has a reviewlock can download
        request = self.factory.get(
            f'/courses/prog1/F2018/submissions/download/{sub.pk}/')
        request.user = self.s3
        self.kwargs['pk'] = sub.pk
        response = DownloadSubmissionView.as_view()(request, **self.kwargs)
        self.assertEqual(response.status_code, 200)
示例#8
0
    def test_student_cannot_download_answer_file_not_owned(self):
        s_exercise = SubmissionExercise.objects.get(name="T1 TEXT")
        r_exercise = ReviewExercise.objects.get(name="T1 TEXT REVIEW")

        sub = OriginalSubmission(course=self.course,
                                 text="juups",
                                 submitter_user=self.s1,
                                 exercise=s_exercise)
        sub.save()

        r_exercise.question_order = ['3']
        r_exercise.save()

        rev_sub = ReviewSubmission(course=self.course,
                                   reviewed_submission=sub,
                                   submitter_user=self.s2,
                                   exercise=r_exercise)
        rev_sub.save()

        temp_file = SimpleUploadedFile(name='lorem_ipsum.txt',
                                       content=bytearray('jada jada', 'utf-8'))

        answer_with_file = Answer(
            question=Question.objects.get(pk=3),
            submission=rev_sub,
            uploaded_file=temp_file,
        )
        answer_with_file.save()

        request = self.factory.get(
            f'/courses/prog1/F2018/submissions/download/{answer_with_file.pk}/?type=answer'
        )
        request.user = self.s3
        self.kwargs['pk'] = answer_with_file.pk

        self.assertRaises(PermissionDenied, DownloadSubmissionView.as_view(),
                          request, **self.kwargs)

        g = StudentGroup(name="g1",
                         course=self.course,
                         student_usernames=[self.s1.email, self.s3.email])
        g.save()
        sub.submitter_group = g
        sub.save()

        for user in self.students + [self.t1]:
            request = self.factory.get(
                f'/courses/prog1/F2018/submissions/download/{answer_with_file.pk}/?type=answer'
            )
            request.user = user
            self.kwargs['pk'] = answer_with_file.pk

            if user == self.s4:
                self.assertRaises(PermissionDenied,
                                  DownloadSubmissionView.as_view(), request,
                                  **self.kwargs)
            else:
                response = DownloadSubmissionView.as_view()(request,
                                                            **self.kwargs)
                self.assertEqual(response.status_code, 200)
示例#9
0
    def test_student_cannot_download_hide_from_receiver_answer_file(self):
        s_exercise = SubmissionExercise.objects.get(name="T1 TEXT")
        r_exercise = ReviewExercise.objects.get(name="T1 TEXT REVIEW")

        sub = OriginalSubmission(course=self.course,
                                 text="juups",
                                 submitter_user=self.s1,
                                 exercise=s_exercise)
        sub.save()

        r_exercise.question_order = ['3']
        r_exercise.save()

        rev_sub = ReviewSubmission(course=self.course,
                                   reviewed_submission=sub,
                                   submitter_user=self.s2,
                                   exercise=r_exercise)
        rev_sub.save()

        temp_file = SimpleUploadedFile(name='lorem_ipsum.txt',
                                       content=bytearray('jada jada', 'utf-8'))
        question = Question.objects.get(pk=3)

        answer_with_file = Answer(
            question=question,
            submission=rev_sub,
            uploaded_file=temp_file,
        )
        answer_with_file.save()

        request = self.factory.get(
            f'/courses/prog1/F2018/submissions/download/{answer_with_file.pk}/?type=answer'
        )
        request.user = self.s1
        self.kwargs['pk'] = answer_with_file.pk

        self.assertEqual(
            DownloadSubmissionView.as_view()(request,
                                             **self.kwargs).status_code, 200)
        question.hide_from_receiver = True
        question.save()
        self.assertRaises(PermissionDenied, DownloadSubmissionView.as_view(),
                          request, **self.kwargs)
示例#10
0
    def test_student_cannot_download_submission_not_owned(self):
        exercise = SubmissionExercise.objects.get(pk=1)

        exercise.type = 'FILE_UPLOAD'
        exercise.accepted_filetypes = '.txt'
        exercise.save()

        temp_file = SimpleUploadedFile(name='lorem_ipsum.txt',
                                       content=bytearray('jada jada', 'utf-8'))
        sub = OriginalSubmission(course=self.course,
                                 file=temp_file,
                                 submitter_user=self.s1,
                                 exercise=exercise)
        sub.save()

        request = self.factory.get(
            f'/courses/prog1/F2018/submissions/download/{sub.pk}/')
        request.user = self.s2
        self.kwargs['pk'] = sub.pk

        self.assertRaises(PermissionDenied, DownloadSubmissionView.as_view(),
                          request, **self.kwargs)
示例#11
0
    def test_teacherCanViewAllSubmissions(self):

        exercise = SubmissionExercise.objects.get(pk=1)

        for username in ["student1", "student2", "student3", "teacher1"]:
            user = User.objects.get(username=username)
            OriginalSubmission(course=self.course,
                               submitter_user=user,
                               exercise=exercise,
                               text="jadajada").save()

        request = self.factory.get(
            '/courses/prog1/F2018/submissions/s/1/list/')
        request.user = User.objects.get(username="******")
        self.kwargs['pk'] = 1

        response = OriginalSubmissionListView.as_view()(request, **self.kwargs)

        self.assertEqual(OriginalSubmission.objects.all().count(), 4)
        self.assertEqual(response.context_data['object_list'].count(), 4)
        self.assertContains(response, "student1")  # hacky
        self.assertContains(response, "student2")
        self.assertContains(response, "student3")
        self.assertContains(response, "teacher1")
示例#12
0
def prepare_group_review_exercise_for(exercise, user, LTI_MODE):
    """
    This is called just before showing the student a group peer-review
    page where the student can peer-review other students in his/her group.

    Because of the design of the system, there has to exist an OriginalSubmission
    for each ReviewSubmission. This function will do two things:

    1. if the receiver of the feedback (student in the same group) has never
       logged into the system (and thus his/her account doesn't exist yet),
       a new temporary user account with his/her email will be created.
       for that new temp user account, temporary=True will be set.
       if the current user is using the system through LTI integration,
       lti=True will also be set since all users of a particular course
       either use the system through LTI or don't. this distinction makes it
       possible for a user to be attending two courses of which one uses
       LTI and one doesn't and the user accounts don't mix mistakenly.

    2. create one OriginalSubmission for each of the group members so that
       the peer-reviews  (ReviewSubmissions) can point to them

    3. when the real user logins in the future, this temporary account will be
       removed and all submissions transerred to the actual, real user account.
       this logic is implemented in prplatform.users.receivers
    """

    course = exercise.course
    group = course.find_studentgroup_by_user(user)

    if not group:
        return

    for student_email in group.student_usernames:
        logger.info(f"FINDING: {student_email}, LTI_MODE: {LTI_MODE}")
        student = User.objects.filter(email=student_email,
                                      lti=LTI_MODE).first()

        if not student:
            logger.info(
                f'ReviewExericse (pk={exercise.pk}): User not found for {student_email} '
                f'(lti={LTI_MODE}) -> creating temp user in perpare_group_review_exercise_for'
            )
            # temp_str distinguishes temp users created through LTI and outside of it
            # for the username is a unique field
            temp_str = 'lti-' if LTI_MODE else ''
            student = User(username=f"temp-{temp_str}{student_email}",
                           email=student_email,
                           lti=LTI_MODE,
                           temporary=True)
            student.save()

        if exercise.reviewable_exercise.submissions \
                                       .filter(submitter_user=student).exists():
            logger.info(f'Prev sub found for {student} --> not creating new')
        else:
            logger.info(f'Prev sub NOT FOUND for {student} --> creating new')
            osub = OriginalSubmission(
                course=course,
                exercise=exercise.reviewable_exercise,
                submitter_user=student,
                text=
                ("This is *automatically* created submission for group peer-review. "
                 "This is needed because every peer-review has to point to some original "
                 "submission."))
            osub.save()
示例#13
0
    def test_reviewsubmissionlist_list_contents(self):

        sub_exercise = SubmissionExercise.objects.get(pk=1)
        rev_exercise = ReviewExercise.objects.get(pk=1)

        for user in self.students[:2]:
            OriginalSubmission(course=self.course,
                               submitter_user=user,
                               exercise=sub_exercise,
                               text="jadajada").save()

        for user in self.students[:2]:
            revsub = OriginalSubmission.objects.filter(exercise=sub_exercise) \
                .exclude(submitter_user=user).first()
            ReviewSubmission(course=self.course,
                             submitter_user=user,
                             exercise=rev_exercise,
                             reviewed_submission=revsub).save()

        # teacher sees all reviews
        request = self.factory.get(
            '/courses/prog1/F2018/submissions/r/1/list/')
        request.user = User.objects.get(username="******")
        self.kwargs['pk'] = 1
        response = ReviewSubmissionListView.as_view()(request, **self.kwargs)
        self.assertEqual(ReviewSubmission.objects.all().count(), 2)
        self.assertEqual(response.context_data['object_list'].count(), 2)
        self.assertContains(response, "student1")  # hacky
        self.assertContains(response, "student2")

        # student1 sees reviews of him by student2
        request = self.factory.get(
            '/courses/prog1/F2018/submissions/r/1/list/?mode=my')
        request.user = self.s1
        self.kwargs['pk'] = 1
        response = ReviewSubmissionListView.as_view()(request, **self.kwargs)
        self.assertEqual(ReviewSubmission.objects.all().count(), 2)
        self.assertEqual(response.context_data['object_list'].count(), 1)
        self.assertEqual(
            response.context_data['object_list'][0].submitter_user, self.s2)

        # student2 sees reviews of him by student1
        request = self.factory.get(
            '/courses/prog1/F2018/submissions/r/1/list/?mode=my')
        request.user = self.s2
        self.kwargs['pk'] = 1
        response = ReviewSubmissionListView.as_view()(request, **self.kwargs)
        self.assertEqual(ReviewSubmission.objects.all().count(), 2)
        self.assertEqual(response.context_data['object_list'].count(), 1)
        self.assertEqual(
            response.context_data['object_list'][0].submitter_user, self.s1)

        # if RE.show_reviews_only_to_teacher, nothing in the list
        rev_exercise.show_reviews_only_to_teacher = True
        rev_exercise.save()

        request = self.factory.get(
            '/courses/prog1/F2018/submissions/r/1/list/?mode=my')
        request.user = self.s2
        self.kwargs['pk'] = 1
        response = ReviewSubmissionListView.as_view()(request, **self.kwargs)
        self.assertEqual(response.context_data['object_list'].count(), 0)
        self.assertContains(response, 'will only be visible')

        rev_exercise.show_reviews_only_to_teacher = False
        rev_exercise.save()

        # reviews by student missing
        rev_exercise.min_submission_count = 100
        rev_exercise.save()

        request = self.factory.get(
            '/courses/prog1/F2018/submissions/r/1/list/?mode=my')
        request.user = self.s2
        self.kwargs['pk'] = 1
        response = ReviewSubmissionListView.as_view()(request, **self.kwargs)
        self.assertEqual(response.context_data['object_list'].count(), 0)
        self.assertContains(response, 'available after completing')

        # available in the future -> students should not see anything
        rev_exercise.min_submission_count = 0
        rev_exercise.show_reviews_after_date = timezone.now(
        ) + datetime.timedelta(days=1)
        rev_exercise.save()

        request = self.factory.get(
            '/courses/prog1/F2018/submissions/r/1/list/?mode=my')
        request.user = self.s2
        self.kwargs['pk'] = 1
        response = ReviewSubmissionListView.as_view()(request, **self.kwargs)
        self.assertEqual(response.context_data['object_list'].count(), 0)
        self.assertContains(response, 'will be available after')
示例#14
0
    def test_reviewsubmissionlist_parties(self):

        sub_exercise = SubmissionExercise.objects.get(pk=1)
        rev_exercise = ReviewExercise.objects.get(pk=1)

        for user in self.students[:2]:
            OriginalSubmission(course=self.course,
                               submitter_user=user,
                               exercise=sub_exercise,
                               text="jadajada").save()

        for user in self.students[:2]:
            revsub = OriginalSubmission.objects.filter(exercise=sub_exercise) \
                .exclude(submitter_user=user).first()
            ReviewSubmission(course=self.course,
                             submitter_user=user,
                             exercise=rev_exercise,
                             reviewed_submission=revsub).save()

        # teacher sees all reviews
        request = self.factory.get(
            '/courses/prog1/F2018/submissions/r/1/list/')
        request.user = User.objects.get(username="******")
        self.kwargs['pk'] = 1
        response = ReviewSubmissionListView.as_view()(request, **self.kwargs)
        self.assertEqual(ReviewSubmission.objects.all().count(), 2)
        self.assertEqual(response.context_data['object_list'].count(), 2)
        self.assertContains(response, "student1")  # hacky
        self.assertContains(response, "student2")

        rev_exercise.type = ReviewExercise.RANDOM
        rev_exercise.save()
        # list doesn't show who reviewed who
        for url in [
                '/courses/prog1/F2018/submissions/r/1/list/',
                '/courses/prog1/F2018/submissions/r/1/list/?mode=my'
        ]:
            request = self.factory.get(url)
            request.user = self.s1
            response = ReviewSubmissionListView.as_view()(request,
                                                          **self.kwargs)
            self.assertNotContains(response, 'Reviewer')
            self.assertNotContains(response, 'Reviewed')
            self.assertNotContains(response, '<td>student2', html=True)
            self.assertNotContains(response, '<td>student1', html=True)

        for typ in [ReviewExercise.CHOOSE, ReviewExercise.GROUP]:
            rev_exercise.type = typ
            rev_exercise.save()
            # student can see who he reviewed
            request = self.factory.get(
                '/courses/prog1/F2018/submissions/r/1/list/')
            request.user = self.s1
            response = ReviewSubmissionListView.as_view()(request,
                                                          **self.kwargs)
            self.assertContains(response, 'Reviewer')
            self.assertContains(response, 'Reviewed')
            self.assertContains(response, '<td>student2', html=True)
            self.assertContains(response, '<td>student1', html=True)

            # student CANNOT see who reviewed him
            request = self.factory.get(
                '/courses/prog1/F2018/submissions/r/1/list/?mode=my')
            request.user = self.s1
            response = ReviewSubmissionListView.as_view()(request,
                                                          **self.kwargs)
            self.assertNotContains(response, 'Reviewer')
            self.assertNotContains(response, 'Reviewed')
            self.assertNotContains(response, '<td>student2', html=True)
            self.assertNotContains(response, '<td>student1', html=True)
示例#15
0
    def test_expiry_hours(self):

        # create original submissions for all 4 students
        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()

        re = ReviewExercise.objects.get(reviewable_exercise=se)

        # create two locks, for s2 and s3, by loading the page
        for s in [self.s2, self.s3]:
            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)

        # make exercise expire locks in 10 hours
        re.reviewlock_expiry_hours = 10
        re.save()

        # move locks 5 hours back in time
        # these locks should NOT expire just yet
        ReviewLock.objects.all().update(created=timezone.now() -
                                        timezone.timedelta(hours=5))

        # load the page -> nothing should just yet expire, third lock should appear
        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.assertEqual(ReviewLock.objects.all().count(), 3)

        # test that created time of a ReviewLock is refreshed on access
        rl_s4 = ReviewLock.objects.get(user=self.s4)
        created_before_refresh = rl_s4.created
        ReviewExerciseDetailView.as_view()(request, **self.kwargs)
        self.assertEqual(ReviewLock.objects.all().count(), 3)
        rl_s4.refresh_from_db()
        self.assertNotEqual(created_before_refresh, rl_s4.created)

        # change expiry to 1 hour -> all locks should be expirying now
        re.reviewlock_expiry_hours = 1
        re.save()

        request.user = self.s1
        # this should create a lock for s1 and expire locks of s2 and s3
        response = ReviewExerciseDetailView.as_view()(request, **self.kwargs)

        self.assertEqual(ReviewLock.objects.all().count(), 2)
        self.assertEqual(
            ReviewLock.objects.filter(user=self.s1).exists(), True)
        self.assertEqual(
            ReviewLock.objects.filter(user=self.s4).exists(), True)

        # make s1 rl expire -> still post the form
        # this simulates how someone may have the browser open for a long time

        rl_s1 = ReviewLock.objects.get(user=self.s1)
        rl_s1.created = rl_s1.created.replace(hour=rl_s1.created.hour - 5)
        rl_s1.save()
        rl_s1_reviewable_pk = rl_s1.original_submission.pk
        # this will expire rl for s1
        request.user = self.s3
        ReviewExerciseDetailView.as_view()(request, **self.kwargs)
        self.assertEqual(
            ReviewLock.objects.filter(user=self.s1).exists(), False)

        # there should be locks for s3 and s4
        self.assertEqual(ReviewLock.objects.all().count(), 2)
        self.assertEqual(
            re.submissions.filter(submitter_user=self.s1).exists(), False)

        answers = {
            'choice': [rl_s1_reviewable_pk],
            'Q-PREFIX-2--question': ['2'],
            'Q-PREFIX-2--value_choice': ['1'],
            'Q-PREFIX-1--question': ['1'],
            'Q-PREFIX-1--value_text': ['some text']
        }
        self.post(re, self.s1, answers)
        self.assertEqual(
            re.submissions.filter(submitter_user=self.s1).exists(), True)
示例#16
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)
示例#17
0
    def test_reviewsubmission_detail_answers(self):

        sub_exercise = SubmissionExercise.objects.get(name='T1 TEXT')
        rev_exercise = ReviewExercise.objects.get(name='T1 TEXT REVIEW')
        rev_exercise.question_order += [3]
        rev_exercise.save()

        for user in self.students[:2]:
            OriginalSubmission(course=self.course,
                               submitter_user=user,
                               exercise=sub_exercise,
                               text="jadajada").save()

        rs_objects = []

        temp_file = SimpleUploadedFile(name='lorem_ipsum.txt',
                                       content=bytearray('jada jada', 'utf-8'))
        for user in self.students[:2]:
            reviewed_sub = OriginalSubmission.objects.filter(exercise=sub_exercise) \
                .exclude(submitter_user=user).first()
            rs = ReviewSubmission.objects.create(
                course=self.course,
                submitter_user=user,
                exercise=rev_exercise,
                reviewed_submission=reviewed_sub)
            rs_objects.append(rs)
            Answer(submission=rs,
                   value_text="juupase juu",
                   question=Question.objects.get(pk=1)).save()
            Answer(submission=rs,
                   value_choice="1",
                   question=Question.objects.get(pk=2)).save()
            Answer(submission=rs,
                   uploaded_file=temp_file,
                   question=Question.objects.get(pk=3)).save()

        # teacher sees all reviews
        request = self.factory.get('/courses/prog1/F2018/submissions/r/1/1/')
        request.user = User.objects.get(username="******")
        self.kwargs['pk'] = rev_exercise.pk
        self.kwargs['sub_pk'] = rs_objects[0].pk
        response = ReviewSubmissionDetailView.as_view()(request, **self.kwargs)
        self.assertContains(response, "juupase juu")
        self.assertContains(response, "Score the work")

        # student sees hidden answer *given* by him
        request = self.factory.get('/courses/prog1/F2018/submissions/r/1/1/')
        request.user = self.s1
        self.kwargs['pk'] = rev_exercise.pk
        self.kwargs['sub_pk'] = rs_objects[0].pk
        response = ReviewSubmissionDetailView.as_view()(request, **self.kwargs)
        self.assertContains(response, "juupase juu")
        self.assertContains(response, "Score the work")

        # student cannot see answer to a hidden question
        request = self.factory.get('/courses/prog1/F2018/submissions/r/1/1/')
        request.user = self.s2
        self.kwargs['pk'] = rev_exercise.pk
        self.kwargs['sub_pk'] = rs_objects[0].pk
        response = ReviewSubmissionDetailView.as_view()(request, **self.kwargs)
        self.assertContains(response, "juupase juu")
        self.assertNotContains(response, "Score the work")
示例#18
0
    def test_reviewsubmission_detail_permissions(self):

        sub_exercise = SubmissionExercise.objects.get(name='T1 TEXT')
        rev_exercise = ReviewExercise.objects.get(name='T1 TEXT REVIEW')
        rev_exercise.question_order += [3]
        rev_exercise.save()

        for user in self.students[:2]:
            OriginalSubmission(course=self.course,
                               submitter_user=user,
                               exercise=sub_exercise,
                               text="jadajada").save()

        rs_objects = []

        temp_file = SimpleUploadedFile(name='lorem_ipsum.txt',
                                       content=bytearray('jada jada', 'utf-8'))
        for user in self.students[:2]:
            reviewed_sub = OriginalSubmission.objects.filter(exercise=sub_exercise) \
                .exclude(submitter_user=user).first()
            rs = ReviewSubmission.objects.create(
                course=self.course,
                submitter_user=user,
                exercise=rev_exercise,
                reviewed_submission=reviewed_sub)
            rs_objects.append(rs)
            Answer(submission=rs,
                   value_text="juupase juu",
                   question=Question.objects.get(pk=1)).save()
            Answer(submission=rs,
                   value_choice="1",
                   question=Question.objects.get(pk=2)).save()
            Answer(submission=rs,
                   uploaded_file=temp_file,
                   question=Question.objects.get(pk=3)).save()

        request = self.factory.get('/courses/prog1/F2018/submissions/r/1/1/')
        request.user = self.s2
        self.kwargs['pk'] = rev_exercise.pk
        self.kwargs['sub_pk'] = rs_objects[0].pk

        # student cannot view feedback if available date in the future
        rev_exercise.show_reviews_after_date = timezone.now(
        ) + timezone.timedelta(hours=1)
        rev_exercise.save()
        self.assertRaises(PermissionDenied,
                          ReviewSubmissionDetailView.as_view(), request,
                          **self.kwargs)
        rev_exercise.show_reviews_after_date = None
        rev_exercise.save()
        self.assertEqual(
            ReviewSubmissionDetailView.as_view()(request,
                                                 **self.kwargs).status_code,
            200)

        # student cannot view feedback if requirements not met
        rev_exercise.min_submission_count = 999
        rev_exercise.save()
        self.assertRaises(PermissionDenied,
                          ReviewSubmissionDetailView.as_view(), request,
                          **self.kwargs)
        rev_exercise.min_submission_count = 0
        rev_exercise.save()
        self.assertEqual(
            ReviewSubmissionDetailView.as_view()(request,
                                                 **self.kwargs).status_code,
            200)

        # receiver *and* owner (feedback to self) can access
        rev_exercise.show_reviews_after_date = timezone.now(
        ) + timezone.timedelta(hours=1)
        rev_exercise.save()
        rs_objects[0].submitter_user = self.s2
        rs_objects[0].save()
        rs_objects[0].reviewed_submission.submitter_user = self.s2
        rs_objects[0].reviewed_submission.save()
        self.assertEqual(
            ReviewSubmissionDetailView.as_view()(request,
                                                 **self.kwargs).status_code,
            200)
        rev_exercise.show_reviews_after_date = None
        rev_exercise.save()

        # third party cannot see anything
        request.user = self.s3
        self.assertRaises(PermissionDenied,
                          ReviewSubmissionDetailView.as_view(), request,
                          **self.kwargs)
示例#19
0
    def test_original_submission_delete_confirmation_page_shows_cascades(self):

        os = OriginalSubmission(
            course=self.course,
            exercise=SubmissionExercise.objects.get(name="T1 TEXT"),
            submitter_user=self.s1,
            text="jada jada jada jada",
        )
        os.save()

        request = self.factory.get(os.get_delete_url())
        self.kwargs['pk'] = os.exercise.pk
        self.kwargs['sub_pk'] = os.pk
        request.user = self.s1

        # students cannot access
        self.assertRaises(PermissionDenied,
                          OriginalSubmissionDeleteView.as_view(), request,
                          **self.kwargs)

        request.user = self.t1
        response = OriginalSubmissionDeleteView.as_view()(request,
                                                          **self.kwargs)
        self.assertContains(response, "No peer-reviews exist yet")

        res = []
        for s in [self.s2, self.s3]:
            re = ReviewSubmission(
                course=self.course,
                exercise=ReviewExercise.objects.get(name="T1 TEXT REVIEW"),
                reviewed_submission=os,
                submitter_user=s,
            )
            re.save()
            res.append(re)

        response = OriginalSubmissionDeleteView.as_view()(request,
                                                          **self.kwargs)
        self.assertNotContains(response, "No peer-reviews exist yet")
        # -> is turned into -&gt; in the response -> just replace that when looking for
        self.assertContains(response, str(res[0]).replace(">", "&gt;"))
        self.assertContains(response, str(res[1]).replace(">", "&gt;"))

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

        request = self.factory.get(res[0].get_delete_url())
        self.kwargs['pk'] = res[0].exercise.pk
        self.kwargs['sub_pk'] = res[0].pk
        request.user = self.s1

        # students cannot access
        self.assertRaises(PermissionDenied,
                          ReviewSubmissionDeleteView.as_view(), request,
                          **self.kwargs)

        # delete page doesn't list any useful information, no need to check

        os.delete()

        self.assertEqual(OriginalSubmission.objects.count(), 0)
        self.assertEqual(ReviewSubmission.objects.count(), 0)
示例#20
0
    def test_download_tokens_allow_downloading(self):

        exercise = SubmissionExercise.objects.get(pk=1)
        exercise.type = 'FILE_UPLOAD'
        exercise.accepted_filetypes = '.txt'
        exercise.save()

        temp_file = SimpleUploadedFile(name='lorem_ipsum.txt',
                                       content=bytearray('jada jada', 'utf-8'))
        sub = OriginalSubmission(course=self.course,
                                 file=temp_file,
                                 submitter_user=self.s1,
                                 exercise=exercise)
        sub.save()

        rev = ReviewSubmission(course=self.course,
                               submitter_user=self.s1,
                               exercise=exercise.review_exercise,
                               reviewed_submission=sub)
        rev.save()

        answer_with_file = Answer(
            question=Question.objects.get(pk=3),
            submission=rev,
            uploaded_file=temp_file,
        )
        answer_with_file.save()

        view_request = self.factory.get(exercise.get_absolute_url() +
                                        "?some=queryparams")
        osub_token = sub.get_download_token_for(self.s1, view_request)
        view_request = self.factory.get(
            exercise.review_exercise.get_absolute_url() + "?some=queryparams")
        rsub_token = rev.get_download_token_for(self.s1, view_request)

        cases = [
            (AnonymousUser, 403, sub, ""),
            (AnonymousUser, 200, sub, f"?dl_token={osub_token}"),
            (AnonymousUser, 403, sub,
             f"?dl_token={osub_token}_THIS_SHOULD_CAUSE_PROBLEMS"),
            (AnonymousUser, 403, answer_with_file, ""),
            (AnonymousUser, 200, answer_with_file, f"&dl_token={rsub_token}"),
            (AnonymousUser, 403, answer_with_file,
             f"&dl_token={rsub_token}_THIS_SHOULD_CAUSE_PROBLEMS"),
        ]

        for user, code, sub, query in cases:
            url = f"{sub.get_file_download_url()}{query}"
            request = self.factory.get(url)
            request.user = user
            self.kwargs['pk'] = sub.pk

            if code == 403:
                self.assertRaises(PermissionDenied,
                                  DownloadSubmissionView.as_view(), request,
                                  **self.kwargs)
            else:
                response = DownloadSubmissionView.as_view()(request,
                                                            **self.kwargs)
                self.assertEqual(response.status_code, code)

        DownloadToken.objects.all().delete()

        for user, _, sub, query in cases:
            url = f"{sub.get_file_download_url()}{query}"
            request = self.factory.get(url)
            request.user = user
            self.kwargs['pk'] = sub.pk
            self.assertRaises(PermissionDenied,
                              DownloadSubmissionView.as_view(), request,
                              **self.kwargs)
示例#21
0
    def test_studentCanOnlyViewPersonalSubmissions(self):

        exercise = SubmissionExercise.objects.get(pk=1)

        for username in ["student1", "student2", "student3"]:
            user = User.objects.get(username=username)
            OriginalSubmission(course=self.course,
                               submitter_user=user,
                               exercise=exercise,
                               text="jadajada").save()

        request = self.factory.get(
            '/courses/prog1/F2018/submissions/s/1/list/')
        request.user = User.objects.get(username="******")
        self.kwargs['pk'] = 1

        response = OriginalSubmissionListView.as_view()(request, **self.kwargs)

        self.assertEqual(OriginalSubmission.objects.all().count(), 3)
        self.assertEqual(response.context_data['object_list'].count(), 1)
        self.assertNotContains(response, "student2")  # hacky
        self.assertNotContains(response, "student3")

        ######################
        #
        # same thing for group submissions
        #

        OriginalSubmission.objects.all().delete()

        g1 = StudentGroup.objects.create(
            course=self.course,
            name='group1',
            student_usernames=['*****@*****.**', '*****@*****.**'])
        g2 = StudentGroup.objects.create(course=self.course,
                                         name='group2',
                                         student_usernames=['*****@*****.**'])

        exercise.use_groups = True
        exercise.save()

        OriginalSubmission(
            course=self.course,
            exercise=exercise,
            text='jada jada',
            submitter_user=User.objects.get(username='******'),
            submitter_group=g1).save()
        # both group members should see 1
        request = self.factory.get(
            '/courses/prog1/F2018/submissions/s/1/list/')
        request.user = User.objects.get(username="******")
        response = OriginalSubmissionListView.as_view()(request, **self.kwargs)
        self.assertEqual(response.context_data['object_list'].count(), 1)
        self.assertEqual(
            response.context_data['object_list'].first().submitter_group, g1)
        self.assertContains(response, 'group1')

        request = self.factory.get(
            '/courses/prog1/F2018/submissions/s/1/list/')
        request.user = User.objects.get(username="******")
        response = OriginalSubmissionListView.as_view()(request, **self.kwargs)
        self.assertEqual(response.context_data['object_list'].count(), 1)
        self.assertEqual(
            response.context_data['object_list'].first().submitter_group, g1)
        self.assertContains(response, 'group1')

        # outsider should see nothing
        request = self.factory.get(
            '/courses/prog1/F2018/submissions/s/1/list/')
        request.user = User.objects.get(username="******")
        response = OriginalSubmissionListView.as_view()(request, **self.kwargs)
        self.assertEqual(response.context_data['object_list'].count(), 0)
        self.assertNotContains(response, 'group1')

        OriginalSubmission(
            course=self.course,
            exercise=exercise,
            text='jada jada',
            submitter_user=User.objects.get(username='******'),
            submitter_group=g1).save()

        OriginalSubmission(
            course=self.course,
            exercise=exercise,
            text='jada jada',
            submitter_user=User.objects.get(username='******'),
            submitter_group=g2).save()

        # g1 nenbers should see two submissions
        request = self.factory.get(
            '/courses/prog1/F2018/submissions/s/1/list/')
        request.user = User.objects.get(username="******")
        response = OriginalSubmissionListView.as_view()(request, **self.kwargs)
        self.assertEqual(response.context_data['object_list'].count(), 2)
        self.assertEqual(
            response.context_data['object_list'].first().submitter_group, g1)
        self.assertNotContains(response, 'group2')
        self.assertContains(response, 'group1')

        request = self.factory.get(
            '/courses/prog1/F2018/submissions/s/1/list/')
        request.user = User.objects.get(username="******")
        response = OriginalSubmissionListView.as_view()(request, **self.kwargs)
        self.assertEqual(response.context_data['object_list'].count(), 2)
        self.assertEqual(
            response.context_data['object_list'].first().submitter_group, g1)
        self.assertNotContains(response, 'group2')
        self.assertContains(response, 'group1')

        # g2 member should see one submission
        request = self.factory.get(
            '/courses/prog1/F2018/submissions/s/1/list/')
        request.user = User.objects.get(username="******")
        response = OriginalSubmissionListView.as_view()(request, **self.kwargs)
        self.assertEqual(response.context_data['object_list'].count(), 1)
        self.assertEqual(
            response.context_data['object_list'].first().submitter_group, g2)
        self.assertNotContains(response, 'group1')
        self.assertContains(response, 'group2')

        # submissions not belonging to any group
        # this could happen if the teacher changed use_groups later on
        OriginalSubmission(
            course=self.course,
            exercise=exercise,
            text='jada jada',
            submitter_user=User.objects.get(username='******'),
        ).save()
        OriginalSubmission(
            course=self.course,
            exercise=exercise,
            text='jada jada',
            submitter_user=User.objects.get(username='******'),
        ).save()
        # student4 should see nothing since he's not in a group and has submitted
        # nothing
        request = self.factory.get(
            '/courses/prog1/F2018/submissions/s/1/list/')
        request.user = User.objects.get(username="******")
        response = OriginalSubmissionListView.as_view()(request, **self.kwargs)
        self.assertEqual(response.context_data['object_list'].count(), 0)
        self.assertNotContains(response, 'group1')
        self.assertNotContains(response, 'group2')
示例#22
0
    def test_ReviewSubmissionDetail_shows_correct_info(self):

        sub_exercise = SubmissionExercise.objects.get(name='T1 TEXT')
        rev_exercise = ReviewExercise.objects.get(name='T1 TEXT REVIEW')

        for user in self.students:
            OriginalSubmission(course=self.course,
                               submitter_user=user,
                               exercise=sub_exercise,
                               text="jadajada").save()

        reviewed = self.s2
        reviewer = self.s1
        reviewed_sub = OriginalSubmission.objects.get(exercise=sub_exercise,
                                                      submitter_user=reviewed)
        rev_sub = ReviewSubmission.objects.create(
            course=self.course,
            submitter_user=reviewer,
            exercise=rev_exercise,
            reviewed_submission=reviewed_sub)

        request = self.factory.get(rev_sub.get_absolute_url())
        self.kwargs['pk'] = rev_exercise.pk
        self.kwargs['sub_pk'] = rev_sub.pk

        rev_exercise.min_submission_count = 0  # so that receiver can view
        rev_exercise.type = ReviewExercise.RANDOM
        rev_exercise.save()

        request.user = self.t1
        response = ReviewSubmissionDetailView.as_view()(request, **self.kwargs)
        self.assertContains(response, "<strong>Submitter")
        self.assertContains(response, "<strong>Reviewed submission")

        request.user = reviewer
        response = ReviewSubmissionDetailView.as_view()(request, **self.kwargs)
        self.assertContains(response, "<strong>Submitter")
        self.assertNotContains(response, "<strong>Reviewed")

        request.user = reviewed
        response = ReviewSubmissionDetailView.as_view()(request, **self.kwargs)
        self.assertNotContains(response, "<strong>Submitter")
        self.assertContains(response, "<strong>Reviewed submission")

        rev_exercise.type = ReviewExercise.CHOOSE
        rev_exercise.save()

        request.user = self.t1
        response = ReviewSubmissionDetailView.as_view()(request, **self.kwargs)
        self.assertContains(response, "<strong>Submitter")
        self.assertContains(response, "<strong>Reviewed submission")

        request.user = reviewer
        response = ReviewSubmissionDetailView.as_view()(request, **self.kwargs)
        self.assertContains(response, "<strong>Submitter")
        self.assertNotContains(response, "<strong>Reviewed submission")
        self.assertContains(response, "<strong>Reviewed student")

        request.user = reviewed
        response = ReviewSubmissionDetailView.as_view()(request, **self.kwargs)
        self.assertNotContains(response, "<strong>Submitter")
        self.assertContains(response, "<strong>Reviewed submission")
        self.assertNotContains(response, "<strong>Reviewed student")

        rev_exercise.type = ReviewExercise.GROUP
        rev_exercise.save()

        request.user = self.t1
        response = ReviewSubmissionDetailView.as_view()(request, **self.kwargs)
        self.assertContains(response, "<strong>Submitter")
        self.assertContains(response, "<strong>Reviewed student")

        request.user = reviewer
        response = ReviewSubmissionDetailView.as_view()(request, **self.kwargs)
        self.assertContains(response, "<strong>Submitter")
        self.assertNotContains(response, "<strong>Reviewed submission")
        self.assertContains(response, "<strong>Reviewed student")

        request.user = reviewed
        response = ReviewSubmissionDetailView.as_view()(request, **self.kwargs)
        self.assertNotContains(response, "<strong>Submitter")
        self.assertNotContains(response, "<strong>Reviewed submission")
        self.assertNotContains(response, "<strong>Reviewed student")