Beispiel #1
0
    def test_delete_answer(self, mocked_update_assignment_grades_run, mocked_update_course_grades_run):
        answer_uuid = self.fixtures.answers[0].uuid

        # test login required
        rv = self.client.delete(self.base_url + '/' + answer_uuid)
        self.assert401(rv)

        # test unauthorized users
        with self.login(self.fixtures.students[1].username):
            rv = self.client.delete(self.base_url + '/' + answer_uuid)
            self.assert403(rv)

        # test invalid answer id
        with self.login(self.fixtures.students[0].username):
            rv = self.client.delete(self.base_url + '/999')
            self.assert404(rv)

            lti_consumer = self.lti_data.lti_consumer
            student = self.fixtures.students[0]
            (lti_user_resource_link1, lti_user_resource_link2) = self.lti_data.setup_student_user_resource_links(
                student, self.fixtures.course, self.fixtures.assignment)

            course_grade = CourseGrade.get_user_course_grade(
                self.fixtures.course, self.fixtures.students[0]).grade
            assignment_grade = AssignmentGrade.get_user_assignment_grade(
                self.fixtures.assignments[0], self.fixtures.students[0]).grade

            # test deletion by author
            rv = self.client.delete(self.base_url + '/' + answer_uuid)
            self.assert200(rv)
            self.assertEqual(answer_uuid, rv.json['id'])

            # grades should decrease
            new_course_grade = CourseGrade.get_user_course_grade(
                self.fixtures.course, self.fixtures.students[0])
            new_assignment_grade = AssignmentGrade.get_user_assignment_grade(
                self.fixtures.assignments[0], self.fixtures.students[0])
            self.assertLess(new_course_grade.grade, course_grade)
            self.assertLess(new_assignment_grade.grade, assignment_grade)

            mocked_update_assignment_grades_run.assert_called_once_with(
                lti_consumer.id,
                [(lti_user_resource_link2.lis_result_sourcedid, new_assignment_grade.id)]
            )
            mocked_update_assignment_grades_run.reset_mock()

            mocked_update_course_grades_run.assert_called_once_with(
                lti_consumer.id,
                [(lti_user_resource_link1.lis_result_sourcedid, new_course_grade.id)]
            )
            mocked_update_course_grades_run.reset_mock()

        # test deletion by user that can manage posts
        with self.login(self.fixtures.instructor.username):
            answer_uuid2 = self.fixtures.answers[1].uuid
            rv = self.client.delete(self.base_url + '/' + answer_uuid2)
            self.assert200(rv)
            self.assertEqual(answer_uuid2, rv.json['id'])
Beispiel #2
0
    def test_delete_answer_comment(self, mocked_update_assignment_grades_run, mocked_update_course_grades_run):
        comment = self.data.get_answer_comments_by_assignment(self.assignment)[0]
        url = self.get_url(
            course_uuid=self.course.uuid, assignment_uuid=self.assignment.uuid,
            answer_uuid=self.answers[self.assignment.id][0].uuid, answer_comment_uuid=comment.uuid)

        # test login required
        rv = self.client.delete(url)
        self.assert401(rv)

        # test unauthorized user
        with self.login(self.data.get_unauthorized_instructor().username):
            rv = self.client.delete(url)
            self.assert403(rv)

        # test invalid comment id
        with self.login(self.data.get_authorized_instructor().username):
            invalid_url = self.get_url(
                course_uuid=self.course.uuid, assignment_uuid=self.assignment.uuid,
                answer_uuid=self.answers[self.assignment.id][0].uuid, answer_comment_uuid="999")
            rv = self.client.delete(invalid_url)
            self.assert404(rv)

            # test authorized instructor
            rv = self.client.delete(url)
            self.assert200(rv)
            self.assertEqual(comment.uuid, rv.json['id'])

        # test author
        with self.login(self.data.get_extra_student(1).username):
            comment = self.data.get_answer_comments_by_assignment(self.assignment)[1]
            url = self.get_url(
                course_uuid=self.course.uuid, assignment_uuid=self.assignment.uuid,
                answer_uuid=self.answers[self.assignment.id][0].uuid, answer_comment_uuid=comment.uuid)
            rv = self.client.delete(url)
            self.assert200(rv)
            self.assertEqual(comment.uuid, rv.json['id'])

        # test delete self-evaulation
        answer = self.answers[self.assignment.id][0]
        self_evaluation = self.data.create_answer_comment(answer.user, answer, comment_type=AnswerCommentType.self_evaluation)
        self.assignment.calculate_grade(answer.user)
        self.course.calculate_grade(answer.user)

        lti_consumer = self.lti_data.lti_consumer
        (lti_user_resource_link1, lti_user_resource_link2) = self.lti_data.setup_student_user_resource_links(
            answer.user, self.course, self.assignment)

        with self.login(self.data.get_authorized_instructor().username):
            course_grade = CourseGrade.get_user_course_grade(self.course, answer.user).grade
            assignment_grade = AssignmentGrade.get_user_assignment_grade(self.assignment, answer.user).grade

            url = self.get_url(
                course_uuid=self.course.uuid, assignment_uuid=self.assignment.uuid,
                answer_uuid=answer.uuid, answer_comment_uuid=self_evaluation.uuid)
            rv = self.client.delete(url)
            self.assert200(rv)
            self.assertEqual(self_evaluation.uuid, rv.json['id'])

            # grades should decrease
            new_course_grade = CourseGrade.get_user_course_grade(self.course, answer.user)
            new_assignment_grade = AssignmentGrade.get_user_assignment_grade(self.assignment, answer.user)
            self.assertLess(new_course_grade.grade, course_grade)
            self.assertLess(new_assignment_grade.grade, assignment_grade)

            mocked_update_assignment_grades_run.assert_called_once_with(
                lti_consumer.id,
                [(lti_user_resource_link2.lis_result_sourcedid, new_assignment_grade.id)]
            )
            mocked_update_assignment_grades_run.reset_mock()

            mocked_update_course_grades_run.assert_called_once_with(
                lti_consumer.id,
                [(lti_user_resource_link1.lis_result_sourcedid, new_course_grade.id)]
            )
            mocked_update_course_grades_run.reset_mock()
Beispiel #3
0
    def test_edit_answer_comment(self, mocked_update_assignment_grades_run, mocked_update_course_grades_run):
        comment = self.data.get_answer_comments_by_assignment(self.assignment)[0]
        url = self.get_url(
            course_uuid=self.course.uuid, assignment_uuid=self.assignment.uuid,
            answer_uuid=self.answers[self.assignment.id][0].uuid, answer_comment_uuid=comment.uuid
        )

        content = {
            'id': comment.uuid,
            'content': 'insightful.',
            'comment_type': AnswerCommentType.private.value
        }
        draft_comment = self.data.get_answer_comments_by_assignment(self.assignment)[2]
        draft_url = self.get_url(
            course_uuid=self.course.uuid, assignment_uuid=self.assignment.uuid,
            answer_uuid=self.answers[self.assignment.id][0].uuid, answer_comment_uuid=draft_comment.uuid)
        draft_content = {
            'id': draft_comment.uuid,
            'content': 'insightful.',
            'comment_type': AnswerCommentType.private.value,
            'draft': True
        }

        # test login required
        rv = self.client.post(url, data=json.dumps(content), content_type='application/json')
        self.assert401(rv)

        # test unauthorized user
        with self.login(self.data.get_unauthorized_instructor().username):
            rv = self.client.post(url, data=json.dumps(content), content_type='application/json')
            self.assert403(rv)

        # test invalid course id
        with self.login(self.data.get_authorized_instructor().username):
            invalid_url = self.get_url(
                course_uuid="999", assignment_uuid=self.assignment.uuid,
                answer_uuid=self.answers[self.assignment.id][0].uuid, answer_comment_uuid=comment.uuid)
            rv = self.client.post(invalid_url, data=json.dumps(content), content_type='application/json')
            self.assert404(rv)

            # test invalid answer id
            invalid_url = self.get_url(
                course_uuid=self.course.uuid, assignment_uuid=self.assignment.uuid,
                answer_uuid="999", answer_comment_uuid=comment.uuid)
            rv = self.client.post(invalid_url, data=json.dumps(content), content_type='application/json')
            self.assert404(rv)

            # test invalid comment id
            invalid_url = self.get_url(
                course_uuid=self.course.uuid, assignment_uuid=self.assignment.uuid,
                answer_uuid=self.answers[self.assignment.id][0].uuid, answer_comment_uuid="999")
            rv = self.client.post(invalid_url, data=json.dumps(content), content_type='application/json')
            self.assert404(rv)

            # test unmatched comment ids
            invalid = content.copy()
            invalid['id'] = self.data.get_answer_comments_by_assignment(self.assignment)[1].uuid
            rv = self.client.post(url, data=json.dumps(invalid), content_type='application/json')
            self.assert400(rv)
            self.assertEqual("Comment id does not match URL.", rv.json['error'])

            # test empty content
            empty = content.copy()
            empty['content'] = ''
            rv = self.client.post(url, data=json.dumps(empty), content_type='application/json')
            self.assert400(rv)
            self.assertEqual("The comment content is empty!", rv.json['error'])

            # test empty comment_type
            empty = content.copy()
            empty['comment_type'] = ''
            rv = self.client.post(url, data=json.dumps(empty), content_type='application/json')
            self.assert400(rv)

        # test authorized instructor
        with self.login(self.data.get_authorized_instructor().username):
            rv = self.client.post(url, data=json.dumps(content), content_type='application/json')
            self.assert200(rv)
            self.assertEqual(content['content'], rv.json['content'])

        # test author
        with self.login(self.data.get_extra_student(0).username):
            content['content'] = 'I am the author'
            rv = self.client.post(url, data=json.dumps(content), content_type='application/json')
            self.assert200(rv)
            self.assertEqual(content['content'], rv.json['content'])
            self.assertFalse(rv.json['draft'])

            # ignored setting draft to True when draft is already False
            content['draft'] = True
            rv = self.client.post(url, data=json.dumps(content), content_type='application/json')
            self.assert200(rv)
            self.assertEqual(content['content'], rv.json['content'])
            self.assertFalse(rv.json['draft'])

        # test draft author
        with self.login(self.data.get_extra_student(1).username):
            draft_content['content'] = 'I am the author'
            rv = self.client.post(draft_url, data=json.dumps(draft_content), content_type='application/json')
            self.assert200(rv)
            self.assertEqual(draft_content['content'], rv.json['content'])
            self.assertTrue(rv.json['draft'])

            # can change draft to False when draft is True
            draft_content['draft'] = False
            rv = self.client.post(draft_url, data=json.dumps(draft_content), content_type='application/json')
            self.assert200(rv)
            self.assertFalse(rv.json['draft'])

        answer = self.answers[self.assignment.id][0]
        self_evaluation = self.data.create_answer_comment(
            answer.user, answer, comment_type=AnswerCommentType.self_evaluation, draft=True)
        self_evaluation_url = self.get_url(
            course_uuid=self.course.uuid, assignment_uuid=self.assignment.uuid,
            answer_uuid=answer.uuid, answer_comment_uuid=self_evaluation.uuid)

        with self.login(answer.user.username):
            lti_consumer = self.lti_data.lti_consumer
            (lti_user_resource_link1, lti_user_resource_link2) = self.lti_data.setup_student_user_resource_links(
                answer.user, self.course, self.assignment)

            course_grade = CourseGrade.get_user_course_grade(self.course, answer.user).grade
            assignment_grade = AssignmentGrade.get_user_assignment_grade(self.assignment, answer.user).grade
            content = {
                'id': self_evaluation.uuid,
                'content': 'insightful.',
                'comment_type': AnswerCommentType.self_evaluation.value,
                'draft': True
            }

            rv = self.client.post(self_evaluation_url, data=json.dumps(content), content_type='application/json')
            self.assert200(rv)
            self.assertEqual(content['content'], rv.json['content'])
            self.assertTrue(rv.json['draft'])

            # grades should not change
            new_course_grade = CourseGrade.get_user_course_grade(self.course, answer.user).grade
            new_assignment_grade = AssignmentGrade.get_user_assignment_grade(self.assignment, answer.user).grade
            self.assertEqual(new_course_grade, course_grade)
            self.assertEqual(new_assignment_grade, assignment_grade)

            # can change draft to False when draft is True
            content['draft'] = False
            rv = self.client.post(self_evaluation_url, data=json.dumps(content), content_type='application/json')
            self.assert200(rv)
            self.assertFalse(rv.json['draft'])

            # grades should increase
            new_course_grade = CourseGrade.get_user_course_grade(self.course, answer.user)
            new_assignment_grade = AssignmentGrade.get_user_assignment_grade(self.assignment, answer.user)
            self.assertGreater(new_course_grade.grade, course_grade)
            self.assertGreater(new_assignment_grade.grade, assignment_grade)

            mocked_update_assignment_grades_run.assert_called_once_with(
                lti_consumer.id,
                [(lti_user_resource_link2.lis_result_sourcedid, new_assignment_grade.id)]
            )
            mocked_update_assignment_grades_run.reset_mock()

            mocked_update_course_grades_run.assert_called_once_with(
                lti_consumer.id,
                [(lti_user_resource_link1.lis_result_sourcedid, new_course_grade.id)]
            )
            mocked_update_course_grades_run.reset_mock()
Beispiel #4
0
    def test_create_answer_comment(self, mocked_update_assignment_grades_run, mocked_update_course_grades_run):
        url = self.get_url(
            course_uuid=self.course.uuid, assignment_uuid=self.assignment.uuid,
            answer_uuid=self.answers[self.assignment.id][0].uuid)
        content = {
            'comment_type': AnswerCommentType.private.value,
            'content': 'great answer'
        }

        # test login required
        rv = self.client.post(url, data=json.dumps(content), content_type='application/json')
        self.assert401(rv)

        # test unauthorized user
        with self.login(self.data.get_unauthorized_instructor().username):
            rv = self.client.post(url, data=json.dumps(content), content_type='application/json')
            self.assert403(rv)

        # test invalid course id
        with self.login(self.data.get_authorized_instructor().username):
            invalid_url = self.get_url(
                course_uuid="999", assignment_uuid=self.assignment.uuid,
                answer_uuid=self.answers[self.assignment.id][0].uuid)
            rv = self.client.post(invalid_url, data=json.dumps(content), content_type='application/json')
            self.assert404(rv)

            # test invalid assignment id
            invalid_url = self.get_url(
                course_uuid=self.course.uuid, assignment_uuid="999",
                answer_uuid=self.answers[self.assignment.id][0].uuid)
            rv = self.client.post(invalid_url, data=json.dumps(content), content_type='application/json')
            self.assert404(rv)

            # test invalid answer id
            invalid_url = self.get_url(
                course_uuid=self.course.uuid, assignment_uuid=self.assignment.uuid, answer_uuid="999")
            rv = self.client.post(invalid_url, data=json.dumps(content), content_type='application/json')
            self.assert404(rv)

            # test empty content
            empty = content.copy()
            empty['content'] = ''
            rv = self.client.post(url, data=json.dumps(empty), content_type='application/json')
            self.assert400(rv)

            # test empty comment type
            empty = content.copy()
            empty['comment_type'] = ''
            rv = self.client.post(url, data=json.dumps(empty), content_type='application/json')
            self.assert400(rv)

            # test authorized user
            rv = self.client.post(url, data=json.dumps(content), content_type='application/json')
            self.assert200(rv)
            self.assertEqual(content['content'], rv.json['content'])
            self.assertFalse(rv.json['draft'])

            # test authorized user draft
            draft_content = content.copy()
            draft_content['draft'] = True
            rv = self.client.post(url, data=json.dumps(draft_content), content_type='application/json')
            self.assert200(rv)
            self.assertEqual(content['content'], rv.json['content'])
            self.assertTrue(rv.json['draft'])

            # test authorized user draft - empty content
            empty = draft_content.copy()
            empty['content'] = None
            rv = self.client.post(url, data=json.dumps(empty), content_type='application/json')
            self.assert200(rv)
            self.assertEqual(empty['content'], rv.json['content'])
            self.assertTrue(rv.json['draft'])

        with self.login(self.data.get_authorized_student().username):
            lti_consumer = self.lti_data.lti_consumer
            (lti_user_resource_link1, lti_user_resource_link2) = self.lti_data.setup_student_user_resource_links(
                self.data.get_authorized_student(), self.course, self.assignment)

            course_grade = CourseGrade.get_user_course_grade(self.course, self.data.get_authorized_student()).grade
            assignment_grade = AssignmentGrade.get_user_assignment_grade(self.assignment, self.data.get_authorized_student()).grade

            content = {
                'comment_type': AnswerCommentType.self_evaluation.value,
                'content': 'great answer'
            }

            rv = self.client.post(url, data=json.dumps(content), content_type='application/json')
            self.assert200(rv)

            # grades should increase
            new_course_grade = CourseGrade.get_user_course_grade(self.course, self.data.get_authorized_student())
            new_assignment_grade = AssignmentGrade.get_user_assignment_grade(self.assignment, self.data.get_authorized_student())
            self.assertGreater(new_course_grade.grade, course_grade)
            self.assertGreater(new_assignment_grade.grade, assignment_grade)

            mocked_update_assignment_grades_run.assert_called_once_with(
                lti_consumer.id,
                [(lti_user_resource_link2.lis_result_sourcedid, new_assignment_grade.id)]
            )
            mocked_update_assignment_grades_run.reset_mock()

            mocked_update_course_grades_run.assert_called_once_with(
                lti_consumer.id,
                [(lti_user_resource_link1.lis_result_sourcedid, new_course_grade.id)]
            )
            mocked_update_assignment_grades_run.reset_mock()
Beispiel #5
0
    def test_get_and_submit_comparison(self, mocked_update_assignment_grades_run, mocked_update_course_grades_run):
        lti_consumer = self.lti_data.lti_consumer
        (lti_user_resource_link1, lti_user_resource_link2) = self.lti_data.setup_student_user_resource_links(
            self.data.get_authorized_student(), self.course, self.assignment)

        users = [self.data.get_authorized_student(), self.data.get_authorized_instructor(), self.data.get_authorized_ta()]
        for user in users:
            compared_answer_uuids = set()
            valid_answer_uuids = set()
            for answer in self.data.get_student_answers():
                if answer.assignment.id == self.assignment.id and answer.user_id != user.id:
                    valid_answer_uuids.add(answer.uuid)

            if user.id == self.data.get_authorized_student().id:
                for comparison_example in self.data.comparisons_examples:
                    if comparison_example.assignment_id == self.assignment.id:
                        valid_answer_uuids.add(comparison_example.answer1_uuid)
                        valid_answer_uuids.add(comparison_example.answer2_uuid)

            with self.login(user.username):
                if user.id in [self.data.get_authorized_instructor().id, self.data.get_authorized_ta().id]:
                    self.assignment.educators_can_compare = False
                    db.session.commit()

                    # cannot compare answers unless educators_can_compare is set for assignment
                    rv = self.client.get(self.base_url)
                    self.assert403(rv)

                    self.assignment.educators_can_compare = True
                    db.session.commit()

                current = 0
                while len(valid_answer_uuids - compared_answer_uuids) > 0:
                    current += 1
                    if user.id == self.data.get_authorized_student().id:
                        course_grade = CourseGrade.get_user_course_grade(self.course, user).grade
                        assignment_grade = AssignmentGrade.get_user_assignment_grade(self.assignment, user).grade

                    # establish expected data by first getting an answer pair
                    rv = self.client.get(self.base_url)
                    self.assert200(rv)
                    actual_answer1_uuid = rv.json['objects'][0]['answer1_id']
                    actual_answer2_uuid = rv.json['objects'][0]['answer2_id']
                    self.assertIn(actual_answer1_uuid, valid_answer_uuids)
                    self.assertIn(actual_answer2_uuid, valid_answer_uuids)
                    self.assertNotEqual(actual_answer1_uuid, actual_answer2_uuid)
                    self.assertTrue(rv.json['new_pair'])
                    self.assertEqual(rv.json['current'], current)

                    # fetch again
                    rv = self.client.get(self.base_url)
                    self.assert200(rv)
                    expected_comparisons = rv.json
                    self.assertEqual(actual_answer1_uuid, rv.json['objects'][0]['answer1_id'])
                    self.assertEqual(actual_answer2_uuid, rv.json['objects'][0]['answer2_id'])
                    self.assertFalse(rv.json['new_pair'])
                    self.assertEqual(rv.json['current'], current)

                    # test draft post
                    comparison_submit = self._build_comparison_submit(rv.json['objects'][0]['answer1_id'], True)
                    rv = self.client.post(
                        self.base_url,
                        data=json.dumps(comparison_submit),
                        content_type='application/json')
                    self.assert200(rv)
                    actual_comparisons = rv.json['objects']
                    self._validate_comparison_submit(comparison_submit, actual_comparisons, expected_comparisons)

                    # test draft post (no answer id)
                    comparison_submit = self._build_comparison_submit(None)
                    rv = self.client.post(
                        self.base_url,
                        data=json.dumps(comparison_submit),
                        content_type='application/json')
                    self.assert200(rv)
                    actual_comparisons = rv.json['objects']
                    self._validate_comparison_submit(comparison_submit, actual_comparisons, expected_comparisons)

                    # test normal post
                    comparison_submit = self._build_comparison_submit(rv.json['objects'][0]['answer1_id'])
                    rv = self.client.post(
                        self.base_url,
                        data=json.dumps(comparison_submit),
                        content_type='application/json')
                    self.assert200(rv)
                    actual_comparisons = rv.json['objects']
                    compared_answer_uuids.add(actual_comparisons[0]['answer1_id'])
                    compared_answer_uuids.add(actual_comparisons[0]['answer2_id'])
                    self._validate_comparison_submit(comparison_submit, actual_comparisons, expected_comparisons)

                    # grades should increase for every comparison
                    if user.id == self.data.get_authorized_student().id:
                        new_course_grade = CourseGrade.get_user_course_grade(self.course, user)
                        new_assignment_grade = AssignmentGrade.get_user_assignment_grade(self.assignment, user)
                        self.assertGreater(new_course_grade.grade, course_grade)
                        self.assertGreater(new_assignment_grade.grade, assignment_grade)

                        mocked_update_course_grades_run.assert_called_once_with(
                            lti_consumer.id,
                            [(lti_user_resource_link1.lis_result_sourcedid, new_course_grade.id)]
                        )
                        mocked_update_course_grades_run.reset_mock()

                        mocked_update_assignment_grades_run.assert_called_once_with(
                            lti_consumer.id,
                            [(lti_user_resource_link2.lis_result_sourcedid, new_assignment_grade.id)]
                        )
                        mocked_update_assignment_grades_run.reset_mock()
                    else:
                        new_course_grade = CourseGrade.get_user_course_grade(self.course, user)
                        new_assignment_grade = AssignmentGrade.get_user_assignment_grade(self.assignment, user)
                        self.assertIsNone(new_course_grade)
                        self.assertIsNone(new_assignment_grade)
                        mocked_update_assignment_grades_run.assert_not_called()
                        mocked_update_course_grades_run.assert_not_called()

                    # Resubmit of same comparison should fail
                    rv = self.client.post(
                        self.base_url,
                        data=json.dumps(comparison_submit),
                        content_type='application/json')
                    self.assert400(rv)

                # all answers has been compared by the user, errors out when trying to get another pair
                rv = self.client.get(self.base_url)
                self.assert400(rv)
Beispiel #6
0
    def test_delete_answer_comment(self, mocked_update_assignment_grades_run,
                                   mocked_update_course_grades_run):
        comment = self.data.get_answer_comments_by_assignment(
            self.assignment)[0]
        url = self.get_url(
            course_uuid=self.course.uuid,
            assignment_uuid=self.assignment.uuid,
            answer_uuid=self.answers[self.assignment.id][0].uuid,
            answer_comment_uuid=comment.uuid)

        # test login required
        rv = self.client.delete(url)
        self.assert401(rv)

        # test unauthorized user
        with self.login(self.data.get_unauthorized_instructor().username):
            rv = self.client.delete(url)
            self.assert403(rv)

        # test invalid comment id
        with self.login(self.data.get_authorized_instructor().username):
            invalid_url = self.get_url(
                course_uuid=self.course.uuid,
                assignment_uuid=self.assignment.uuid,
                answer_uuid=self.answers[self.assignment.id][0].uuid,
                answer_comment_uuid="999")
            rv = self.client.delete(invalid_url)
            self.assert404(rv)

            # test authorized instructor
            rv = self.client.delete(url)
            self.assert200(rv)
            self.assertEqual(comment.uuid, rv.json['id'])

        # test author with impersonation
        student = self.data.get_extra_student(1)
        with self.impersonate(self.data.get_authorized_instructor(), student):
            url = self.get_url(
                course_uuid=self.course.uuid,
                assignment_uuid=self.assignment.uuid,
                answer_uuid=self.answers[self.assignment.id][0].uuid,
                answer_comment_uuid=comment.uuid)
            rv = self.client.delete(url)
            self.assert403(rv)
            self.assertTrue(rv.json['disabled_by_impersonation'])

        # test author
        with self.login(self.data.get_extra_student(1).username):
            comment = self.data.get_answer_comments_by_assignment(
                self.assignment)[1]
            url = self.get_url(
                course_uuid=self.course.uuid,
                assignment_uuid=self.assignment.uuid,
                answer_uuid=self.answers[self.assignment.id][0].uuid,
                answer_comment_uuid=comment.uuid)
            rv = self.client.delete(url)
            self.assert200(rv)
            self.assertEqual(comment.uuid, rv.json['id'])

        # test delete self-evaulation with impersonation
        answers = self.answers[self.assignment.id]
        for answer in [
                a for a in answers if a.user.system_role == SystemRole.student
        ]:
            self_evaluation = self.data.create_answer_comment(
                answer.user,
                answer,
                comment_type=AnswerCommentType.self_evaluation,
                draft=True)

            with self.impersonate(self.data.get_authorized_instructor(),
                                  answer.user):
                url = self.get_url(course_uuid=self.course.uuid,
                                   assignment_uuid=self.assignment.uuid,
                                   answer_uuid=answer.uuid,
                                   answer_comment_uuid=self_evaluation.uuid)
                rv = self.client.delete(url)
                self.assert403(rv)
                self.assertTrue(rv.json['disabled_by_impersonation'])

        # test delete self-evaulation
        answer = self.answers[self.assignment.id][0]
        self_evaluation = self.data.create_answer_comment(
            answer.user,
            answer,
            comment_type=AnswerCommentType.self_evaluation)
        self.assignment.calculate_grade(answer.user)
        self.course.calculate_grade(answer.user)

        lti_consumer = self.lti_data.lti_consumer
        (lti_user_resource_link1, lti_user_resource_link2
         ) = self.lti_data.setup_student_user_resource_links(
             answer.user, self.course, self.assignment)

        with self.login(self.data.get_authorized_instructor().username):
            course_grade = CourseGrade.get_user_course_grade(
                self.course, answer.user).grade
            assignment_grade = AssignmentGrade.get_user_assignment_grade(
                self.assignment, answer.user).grade

            url = self.get_url(course_uuid=self.course.uuid,
                               assignment_uuid=self.assignment.uuid,
                               answer_uuid=answer.uuid,
                               answer_comment_uuid=self_evaluation.uuid)
            rv = self.client.delete(url)
            self.assert200(rv)
            self.assertEqual(self_evaluation.uuid, rv.json['id'])

            # grades should decrease
            new_course_grade = CourseGrade.get_user_course_grade(
                self.course, answer.user)
            new_assignment_grade = AssignmentGrade.get_user_assignment_grade(
                self.assignment, answer.user)
            self.assertLess(new_course_grade.grade, course_grade)
            self.assertLess(new_assignment_grade.grade, assignment_grade)

            mocked_update_assignment_grades_run.assert_called_once_with(
                lti_consumer.id, [[
                    lti_user_resource_link2.lis_result_sourcedid,
                    new_assignment_grade.id
                ]])
            mocked_update_assignment_grades_run.reset_mock()

            mocked_update_course_grades_run.assert_called_once_with(
                lti_consumer.id, [[
                    lti_user_resource_link1.lis_result_sourcedid,
                    new_course_grade.id
                ]])
            mocked_update_course_grades_run.reset_mock()
Beispiel #7
0
    def test_edit_answer_comment(self, mocked_update_assignment_grades_run,
                                 mocked_update_course_grades_run):
        comment = self.data.get_answer_comments_by_assignment(
            self.assignment)[0]
        url = self.get_url(
            course_uuid=self.course.uuid,
            assignment_uuid=self.assignment.uuid,
            answer_uuid=self.answers[self.assignment.id][0].uuid,
            answer_comment_uuid=comment.uuid)

        content = {
            'id': comment.uuid,
            'content': 'insightful.',
            'comment_type': AnswerCommentType.private.value
        }
        draft_comment = self.data.get_answer_comments_by_assignment(
            self.assignment)[2]
        draft_url = self.get_url(
            course_uuid=self.course.uuid,
            assignment_uuid=self.assignment.uuid,
            answer_uuid=self.answers[self.assignment.id][0].uuid,
            answer_comment_uuid=draft_comment.uuid)
        draft_content = {
            'id': draft_comment.uuid,
            'content': 'insightful.',
            'comment_type': AnswerCommentType.private.value,
            'draft': True
        }

        # test login required
        rv = self.client.post(url,
                              data=json.dumps(content),
                              content_type='application/json')
        self.assert401(rv)

        # test unauthorized user
        with self.login(self.data.get_unauthorized_instructor().username):
            rv = self.client.post(url,
                                  data=json.dumps(content),
                                  content_type='application/json')
            self.assert403(rv)

        # test invalid course id
        with self.login(self.data.get_authorized_instructor().username):
            invalid_url = self.get_url(
                course_uuid="999",
                assignment_uuid=self.assignment.uuid,
                answer_uuid=self.answers[self.assignment.id][0].uuid,
                answer_comment_uuid=comment.uuid)
            rv = self.client.post(invalid_url,
                                  data=json.dumps(content),
                                  content_type='application/json')
            self.assert404(rv)

            # test invalid answer id
            invalid_url = self.get_url(course_uuid=self.course.uuid,
                                       assignment_uuid=self.assignment.uuid,
                                       answer_uuid="999",
                                       answer_comment_uuid=comment.uuid)
            rv = self.client.post(invalid_url,
                                  data=json.dumps(content),
                                  content_type='application/json')
            self.assert404(rv)

            # test invalid comment id
            invalid_url = self.get_url(
                course_uuid=self.course.uuid,
                assignment_uuid=self.assignment.uuid,
                answer_uuid=self.answers[self.assignment.id][0].uuid,
                answer_comment_uuid="999")
            rv = self.client.post(invalid_url,
                                  data=json.dumps(content),
                                  content_type='application/json')
            self.assert404(rv)

            # test unmatched comment ids
            invalid = content.copy()
            invalid['id'] = self.data.get_answer_comments_by_assignment(
                self.assignment)[1].uuid
            rv = self.client.post(url,
                                  data=json.dumps(invalid),
                                  content_type='application/json')
            self.assert400(rv)
            self.assertEqual("Feedback Not Saved", rv.json['title'])
            self.assertEqual(
                "The feedback's ID does not match the URL, which is required in order to save the feedback.",
                rv.json['message'])

            # test empty content
            empty = content.copy()
            empty['content'] = ''
            rv = self.client.post(url,
                                  data=json.dumps(empty),
                                  content_type='application/json')
            self.assert400(rv)
            self.assertEqual("Feedback Not Saved", rv.json['title'])
            self.assertEqual(
                "Please provide content in the text editor and try saving again.",
                rv.json['message'])

            # test empty comment_type
            empty = content.copy()
            empty['comment_type'] = ''
            rv = self.client.post(url,
                                  data=json.dumps(empty),
                                  content_type='application/json')
            self.assert400(rv)

        # test authorized instructor
        with self.login(self.data.get_authorized_instructor().username):
            with mail.record_messages() as outbox:
                rv = self.client.post(url,
                                      data=json.dumps(content),
                                      content_type='application/json')
                self.assert200(rv)
                self.assertEqual(content['content'], rv.json['content'])
                self.assertIn('fullname', rv.json['user'])

                self.assertEqual(len(outbox), 0)

        # test author
        with self.login(self.data.get_extra_student(0).username):

            # test student can not change comment to self-eval / eval
            invalid = content.copy()
            invalid['comment_type'] = AnswerCommentType.self_evaluation.value
            rv = self.client.post(url,
                                  data=json.dumps(invalid),
                                  content_type='application/json')
            self.assert400(rv)
            self.assertEqual("Feedback Not Saved", rv.json['title'])
            self.assertEqual(
                "Feedback type cannot be changed. Please contact support for assistance.",
                rv.json['message'])

            invalid = content.copy()
            invalid['comment_type'] = AnswerCommentType.evaluation.value
            rv = self.client.post(url,
                                  data=json.dumps(invalid),
                                  content_type='application/json')
            self.assert400(rv)
            self.assertEqual("Feedback Not Saved", rv.json['title'])
            self.assertEqual(
                "Feedback type cannot be changed. Please contact support for assistance.",
                rv.json['message'])

            with mail.record_messages() as outbox:
                content['content'] = 'I am the author'
                rv = self.client.post(url,
                                      data=json.dumps(content),
                                      content_type='application/json')
                self.assert200(rv)
                self.assertEqual(content['content'], rv.json['content'])
                self.assertFalse(rv.json['draft'])
                self.assertNotIn('fullname', rv.json['user'])

                self.assertEqual(len(outbox), 0)

            # ignored setting draft to True when draft is already False
            with mail.record_messages() as outbox:
                content['draft'] = True
                rv = self.client.post(url,
                                      data=json.dumps(content),
                                      content_type='application/json')
                self.assert200(rv)
                self.assertEqual(content['content'], rv.json['content'])
                self.assertFalse(rv.json['draft'])
                self.assertNotIn('fullname', rv.json['user'])

                self.assertEqual(len(outbox), 0)

        # test author with impersonation
        student = self.data.get_extra_student(0)
        with self.impersonate(self.data.get_authorized_instructor(), student):
            content['content'] = 'I am the author'
            rv = self.client.post(url,
                                  data=json.dumps(content),
                                  content_type='application/json')
            self.assert403(rv)
            self.assertTrue(rv.json['disabled_by_impersonation'])

            content['draft'] = True
            rv = self.client.post(url,
                                  data=json.dumps(content),
                                  content_type='application/json')
            self.assert403(rv)
            self.assertTrue(rv.json['disabled_by_impersonation'])

        # test draft author
        with self.login(self.data.get_extra_student(1).username):
            with mail.record_messages() as outbox:
                draft_content['content'] = 'I am the author'
                rv = self.client.post(draft_url,
                                      data=json.dumps(draft_content),
                                      content_type='application/json')
                self.assert200(rv)
                self.assertEqual(draft_content['content'], rv.json['content'])
                self.assertTrue(rv.json['draft'])
                self.assertNotIn('fullname', rv.json['user'])

                self.assertEqual(len(outbox), 0)

            # can change draft to False when draft is True
            with mail.record_messages() as outbox:
                draft_content['draft'] = False
                rv = self.client.post(draft_url,
                                      data=json.dumps(draft_content),
                                      content_type='application/json')
                self.assert200(rv)
                self.assertFalse(rv.json['draft'])
                self.assertNotIn('fullname', rv.json['user'])

                self.assertEqual(len(outbox), 1)
                self.assertEqual(
                    outbox[0].subject,
                    "New Answer Feedback in " + self.data.get_course().name)
                self.assertEqual(
                    outbox[0].recipients,
                    [self.answers[self.assignment.id][0].user.email])

        # test draft author with impersonation
        student = self.data.get_extra_student(1)
        with self.impersonate(self.data.get_authorized_instructor(), student):
            draft_content['content'] = 'I am the author'
            rv = self.client.post(draft_url,
                                  data=json.dumps(draft_content),
                                  content_type='application/json')
            self.assert403(rv)
            self.assertTrue(rv.json['disabled_by_impersonation'])

            # cant change draft to False
            draft_content['draft'] = False
            rv = self.client.post(draft_url,
                                  data=json.dumps(draft_content),
                                  content_type='application/json')
            self.assert403(rv)
            self.assertTrue(rv.json['disabled_by_impersonation'])

        answer = self.answers[self.assignment.id][0]
        self_evaluation = self.data.create_answer_comment(
            answer.user,
            answer,
            comment_type=AnswerCommentType.self_evaluation,
            draft=True)
        self_evaluation_url = self.get_url(
            course_uuid=self.course.uuid,
            assignment_uuid=self.assignment.uuid,
            answer_uuid=answer.uuid,
            answer_comment_uuid=self_evaluation.uuid)

        with self.login(answer.user.username):
            lti_consumer = self.lti_data.lti_consumer
            (lti_user_resource_link1, lti_user_resource_link2
             ) = self.lti_data.setup_student_user_resource_links(
                 answer.user, self.course, self.assignment)

            course_grade = CourseGrade.get_user_course_grade(
                self.course, answer.user).grade
            assignment_grade = AssignmentGrade.get_user_assignment_grade(
                self.assignment, answer.user).grade
            content = {
                'id': self_evaluation.uuid,
                'content': 'insightful.',
                'comment_type': AnswerCommentType.self_evaluation.value,
                'draft': True
            }

            # test student can not submit self-eval after self-eval grace period
            orig_answer_end = self.assignment.answer_end
            self.assignment.answer_end = datetime.datetime.utcnow(
            ) - datetime.timedelta(hours=12)
            self.assignment.self_eval_start = datetime.datetime.utcnow(
            ) - datetime.timedelta(hours=1)
            self.assignment.self_eval_end = datetime.datetime.utcnow(
            ) - datetime.timedelta(minutes=10)

            db.session.add(self.assignment)
            db.session.commit()

            rv = self.client.post(self_evaluation_url,
                                  data=json.dumps(content),
                                  content_type='application/json')
            self.assert403(rv)
            self.assertEqual("Self-Evaluation Not Saved", rv.json['title'])
            self.assertEqual(
                "Sorry, the self-evaluation deadline has passed and therefore cannot be submitted.",
                rv.json['message'])

            self.assignment.answer_end = orig_answer_end
            self.assignment.self_eval_start = None
            self.assignment.self_eval_end = None

            with mail.record_messages() as outbox:
                self.assignment.answer_end = datetime.datetime.utcnow(
                ) - datetime.timedelta(hours=12)
                rv = self.client.post(self_evaluation_url,
                                      data=json.dumps(content),
                                      content_type='application/json')
                self.assert200(rv)
                self.assertEqual(content['content'], rv.json['content'])
                self.assertTrue(rv.json['draft'])
                self.assertNotIn('fullname', rv.json['user'])

                self.assertEqual(len(outbox), 0)

                # grades should not change
                new_course_grade = CourseGrade.get_user_course_grade(
                    self.course, answer.user).grade
                new_assignment_grade = AssignmentGrade.get_user_assignment_grade(
                    self.assignment, answer.user).grade
                self.assertEqual(new_course_grade, course_grade)
                self.assertEqual(new_assignment_grade, assignment_grade)

            # can change draft to False when draft is True
            with mail.record_messages() as outbox:
                content['draft'] = False
                rv = self.client.post(self_evaluation_url,
                                      data=json.dumps(content),
                                      content_type='application/json')
                self.assert200(rv)
                self.assertFalse(rv.json['draft'])
                self.assertNotIn('fullname', rv.json['user'])

                self.assertEqual(len(outbox), 0)

                # grades should increase
                new_course_grade = CourseGrade.get_user_course_grade(
                    self.course, answer.user)
                new_assignment_grade = AssignmentGrade.get_user_assignment_grade(
                    self.assignment, answer.user)
                self.assertGreater(new_course_grade.grade, course_grade)
                self.assertGreater(new_assignment_grade.grade,
                                   assignment_grade)

                mocked_update_assignment_grades_run.assert_called_once_with(
                    lti_consumer.id, [[
                        lti_user_resource_link2.lis_result_sourcedid,
                        new_assignment_grade.id
                    ]])
                mocked_update_assignment_grades_run.reset_mock()

                mocked_update_course_grades_run.assert_called_once_with(
                    lti_consumer.id, [[
                        lti_user_resource_link1.lis_result_sourcedid,
                        new_course_grade.id
                    ]])
                mocked_update_course_grades_run.reset_mock()

        # test self-evaluation with impersonation
        answers = self.answers[self.assignment.id]
        for answer in [
                a for a in answers if a.user.system_role == SystemRole.student
        ]:
            self_evaluation = self.data.create_answer_comment(
                answer.user,
                answer,
                comment_type=AnswerCommentType.self_evaluation,
                draft=True)
            self_evaluation_url = self.get_url(
                course_uuid=self.course.uuid,
                assignment_uuid=self.assignment.uuid,
                answer_uuid=answer.uuid,
                answer_comment_uuid=self_evaluation.uuid)

            with self.impersonate(self.data.get_authorized_instructor(),
                                  answer.user):
                content = {
                    'id': self_evaluation.uuid,
                    'content': 'insightful.',
                    'comment_type': AnswerCommentType.self_evaluation.value,
                    'draft': True
                }

                rv = self.client.post(self_evaluation_url,
                                      data=json.dumps(content),
                                      content_type='application/json')
                self.assert403(rv)
                self.assertTrue(rv.json['disabled_by_impersonation'])
                # attempt to change draft to False
                content['draft'] = False
                rv = self.client.post(self_evaluation_url,
                                      data=json.dumps(content),
                                      content_type='application/json')
                self.assert403(rv)
                self.assertTrue(rv.json['disabled_by_impersonation'])
Beispiel #8
0
    def test_create_answer_comment(self, mocked_update_assignment_grades_run,
                                   mocked_update_course_grades_run):
        url = self.get_url(
            course_uuid=self.course.uuid,
            assignment_uuid=self.assignment.uuid,
            answer_uuid=self.answers[self.assignment.id][0].uuid)
        content = {
            'comment_type': AnswerCommentType.private.value,
            'content': 'great answer'
        }

        # test login required
        rv = self.client.post(url,
                              data=json.dumps(content),
                              content_type='application/json')
        self.assert401(rv)

        # test unauthorized user
        with self.login(self.data.get_unauthorized_instructor().username):
            rv = self.client.post(url,
                                  data=json.dumps(content),
                                  content_type='application/json')
            self.assert403(rv)

        # test invalid course id
        with self.login(self.data.get_authorized_instructor().username):
            invalid_url = self.get_url(
                course_uuid="999",
                assignment_uuid=self.assignment.uuid,
                answer_uuid=self.answers[self.assignment.id][0].uuid)
            rv = self.client.post(invalid_url,
                                  data=json.dumps(content),
                                  content_type='application/json')
            self.assert404(rv)

            # test invalid assignment id
            invalid_url = self.get_url(
                course_uuid=self.course.uuid,
                assignment_uuid="999",
                answer_uuid=self.answers[self.assignment.id][0].uuid)
            rv = self.client.post(invalid_url,
                                  data=json.dumps(content),
                                  content_type='application/json')
            self.assert404(rv)

            # test invalid answer id
            invalid_url = self.get_url(course_uuid=self.course.uuid,
                                       assignment_uuid=self.assignment.uuid,
                                       answer_uuid="999")
            rv = self.client.post(invalid_url,
                                  data=json.dumps(content),
                                  content_type='application/json')
            self.assert404(rv)

            # test empty content
            empty = content.copy()
            empty['content'] = ''
            rv = self.client.post(url,
                                  data=json.dumps(empty),
                                  content_type='application/json')
            self.assert400(rv)

            # test empty comment type
            empty = content.copy()
            empty['comment_type'] = ''
            rv = self.client.post(url,
                                  data=json.dumps(empty),
                                  content_type='application/json')
            self.assert400(rv)

            # test authorized user
            with mail.record_messages() as outbox:
                rv = self.client.post(url,
                                      data=json.dumps(content),
                                      content_type='application/json')
                self.assert200(rv)
                self.assertEqual(content['content'], rv.json['content'])
                self.assertFalse(rv.json['draft'])
                self.assertIn('fullname', rv.json['user'])

                self.assertEqual(len(outbox), 1)
                self.assertEqual(
                    outbox[0].subject,
                    "New Answer Feedback in " + self.data.get_course().name)
                self.assertEqual(
                    outbox[0].recipients,
                    [self.answers[self.assignment.id][0].user.email])

            # test authorized user draft
            with mail.record_messages() as outbox:
                draft_content = content.copy()
                draft_content['draft'] = True
                rv = self.client.post(url,
                                      data=json.dumps(draft_content),
                                      content_type='application/json')
                self.assert200(rv)
                self.assertEqual(content['content'], rv.json['content'])
                self.assertTrue(rv.json['draft'])

                self.assertEqual(len(outbox), 0)

            # test authorized user draft - empty content
            with mail.record_messages() as outbox:
                empty = draft_content.copy()
                empty['content'] = None
                rv = self.client.post(url,
                                      data=json.dumps(empty),
                                      content_type='application/json')
                self.assert200(rv)
                self.assertEqual(empty['content'], rv.json['content'])
                self.assertTrue(rv.json['draft'])

                self.assertEqual(len(outbox), 0)

        with self.login('root'):
            with mail.record_messages() as outbox:
                rv = self.client.post(url,
                                      data=json.dumps(content),
                                      content_type='application/json')
                self.assert200(rv)
                self.assertEqual(len(outbox), 1)
                self.assertIn('fullname', rv.json['user'])

        with self.login(self.data.get_authorized_student().username):
            lti_consumer = self.lti_data.lti_consumer
            (lti_user_resource_link1, lti_user_resource_link2
             ) = self.lti_data.setup_student_user_resource_links(
                 self.data.get_authorized_student(), self.course,
                 self.assignment)

            course_grade = CourseGrade.get_user_course_grade(
                self.course, self.data.get_authorized_student()).grade
            assignment_grade = AssignmentGrade.get_user_assignment_grade(
                self.assignment, self.data.get_authorized_student()).grade

            content = {
                'comment_type': AnswerCommentType.self_evaluation.value,
                'content': 'great answer'
            }

            # test student can not submit self-eval after self-eval grace period
            orig_answer_end = self.assignment.answer_end
            self.assignment.answer_end = datetime.datetime.utcnow(
            ) - datetime.timedelta(hours=12)
            self.assignment.self_eval_start = datetime.datetime.utcnow(
            ) - datetime.timedelta(hours=1)
            self.assignment.self_eval_end = datetime.datetime.utcnow(
            ) - datetime.timedelta(minutes=10)

            db.session.add(self.assignment)
            db.session.commit()

            rv = self.client.post(url,
                                  data=json.dumps(content),
                                  content_type='application/json')
            self.assert403(rv)
            self.assertEqual("Self-Evaluation Not Saved", rv.json['title'])
            self.assertEqual(
                "Sorry, the self-evaluation deadline has passed and therefore cannot be submitted.",
                rv.json['message'])

            self.assignment.answer_end = orig_answer_end
            self.assignment.self_eval_start = None
            self.assignment.self_eval_end = None

            with mail.record_messages() as outbox:
                orig_answer_end = self.assignment.answer_end
                self.assignment.answer_end = datetime.datetime.utcnow(
                ) - datetime.timedelta(hours=12)

                rv = self.client.post(url,
                                      data=json.dumps(content),
                                      content_type='application/json')
                self.assert200(rv)

                self.assertEqual(len(outbox), 0)
                self.assertNotIn('fullname', rv.json['user'])

                # grades should increase
                new_course_grade = CourseGrade.get_user_course_grade(
                    self.course, self.data.get_authorized_student())
                new_assignment_grade = AssignmentGrade.get_user_assignment_grade(
                    self.assignment, self.data.get_authorized_student())
                self.assertGreater(new_course_grade.grade, course_grade)
                self.assertGreater(new_assignment_grade.grade,
                                   assignment_grade)

                mocked_update_assignment_grades_run.assert_called_once_with(
                    lti_consumer.id, [[
                        lti_user_resource_link2.lis_result_sourcedid,
                        new_assignment_grade.id
                    ]])
                mocked_update_assignment_grades_run.reset_mock()

                mocked_update_course_grades_run.assert_called_once_with(
                    lti_consumer.id, [[
                        lti_user_resource_link1.lis_result_sourcedid,
                        new_course_grade.id
                    ]])
                mocked_update_assignment_grades_run.reset_mock()

                self.assignment.answer_end = orig_answer_end

        # test with impersonation
        student = self.data.get_extra_student(0)
        with self.impersonate(self.data.get_authorized_instructor(), student):
            lti_consumer = self.lti_data.lti_consumer
            (lti_user_resource_link1, lti_user_resource_link2
             ) = self.lti_data.setup_student_user_resource_links(
                 self.data.get_authorized_student(), self.course,
                 self.assignment)

            course_grade = CourseGrade.get_user_course_grade(
                self.course, self.data.get_authorized_student()).grade
            assignment_grade = AssignmentGrade.get_user_assignment_grade(
                self.assignment, self.data.get_authorized_student()).grade

            content = {
                'comment_type': AnswerCommentType.self_evaluation.value,
                'content': 'great answer'
            }

            with mail.record_messages() as outbox:
                rv = self.client.post(url,
                                      data=json.dumps(content),
                                      content_type='application/json')
                self.assert403(rv)
                self.assertTrue(rv.json['disabled_by_impersonation'])
Beispiel #9
0
    def test_edit_answer_comment(self, mocked_update_assignment_grades_run,
                                 mocked_update_course_grades_run):
        comment = self.data.get_answer_comments_by_assignment(
            self.assignment)[0]
        url = self.get_url(
            course_uuid=self.course.uuid,
            assignment_uuid=self.assignment.uuid,
            answer_uuid=self.answers[self.assignment.id][0].uuid,
            answer_comment_uuid=comment.uuid)

        content = {
            'id': comment.uuid,
            'content': 'insightful.',
            'comment_type': AnswerCommentType.private.value
        }
        draft_comment = self.data.get_answer_comments_by_assignment(
            self.assignment)[2]
        draft_url = self.get_url(
            course_uuid=self.course.uuid,
            assignment_uuid=self.assignment.uuid,
            answer_uuid=self.answers[self.assignment.id][0].uuid,
            answer_comment_uuid=draft_comment.uuid)
        draft_content = {
            'id': draft_comment.uuid,
            'content': 'insightful.',
            'comment_type': AnswerCommentType.private.value,
            'draft': True
        }

        # test login required
        rv = self.client.post(url,
                              data=json.dumps(content),
                              content_type='application/json')
        self.assert401(rv)

        # test unauthorized user
        with self.login(self.data.get_unauthorized_instructor().username):
            rv = self.client.post(url,
                                  data=json.dumps(content),
                                  content_type='application/json')
            self.assert403(rv)

        # test invalid course id
        with self.login(self.data.get_authorized_instructor().username):
            invalid_url = self.get_url(
                course_uuid="999",
                assignment_uuid=self.assignment.uuid,
                answer_uuid=self.answers[self.assignment.id][0].uuid,
                answer_comment_uuid=comment.uuid)
            rv = self.client.post(invalid_url,
                                  data=json.dumps(content),
                                  content_type='application/json')
            self.assert404(rv)

            # test invalid answer id
            invalid_url = self.get_url(course_uuid=self.course.uuid,
                                       assignment_uuid=self.assignment.uuid,
                                       answer_uuid="999",
                                       answer_comment_uuid=comment.uuid)
            rv = self.client.post(invalid_url,
                                  data=json.dumps(content),
                                  content_type='application/json')
            self.assert404(rv)

            # test invalid comment id
            invalid_url = self.get_url(
                course_uuid=self.course.uuid,
                assignment_uuid=self.assignment.uuid,
                answer_uuid=self.answers[self.assignment.id][0].uuid,
                answer_comment_uuid="999")
            rv = self.client.post(invalid_url,
                                  data=json.dumps(content),
                                  content_type='application/json')
            self.assert404(rv)

            # test unmatched comment ids
            invalid = content.copy()
            invalid['id'] = self.data.get_answer_comments_by_assignment(
                self.assignment)[1].uuid
            rv = self.client.post(url,
                                  data=json.dumps(invalid),
                                  content_type='application/json')
            self.assert400(rv)
            self.assertEqual("Reply Not Saved", rv.json['title'])
            self.assertEqual(
                "The reply's ID does not match the URL, which is required in order to save the reply.",
                rv.json['message'])

            # test empty content
            empty = content.copy()
            empty['content'] = ''
            rv = self.client.post(url,
                                  data=json.dumps(empty),
                                  content_type='application/json')
            self.assert400(rv)
            self.assertEqual("Reply Not Saved", rv.json['title'])
            self.assertEqual(
                "Please provide content in the text editor to reply and try saving again.",
                rv.json['message'])

            # test empty comment_type
            empty = content.copy()
            empty['comment_type'] = ''
            rv = self.client.post(url,
                                  data=json.dumps(empty),
                                  content_type='application/json')
            self.assert400(rv)

        # test authorized instructor
        with self.login(self.data.get_authorized_instructor().username):
            with mail.record_messages() as outbox:
                rv = self.client.post(url,
                                      data=json.dumps(content),
                                      content_type='application/json')
                self.assert200(rv)
                self.assertEqual(content['content'], rv.json['content'])

                self.assertEqual(len(outbox), 0)

        # test author
        with self.login(self.data.get_extra_student(0).username):
            with mail.record_messages() as outbox:
                content['content'] = 'I am the author'
                rv = self.client.post(url,
                                      data=json.dumps(content),
                                      content_type='application/json')
                self.assert200(rv)
                self.assertEqual(content['content'], rv.json['content'])
                self.assertFalse(rv.json['draft'])

                self.assertEqual(len(outbox), 0)

            # ignored setting draft to True when draft is already False
            with mail.record_messages() as outbox:
                content['draft'] = True
                rv = self.client.post(url,
                                      data=json.dumps(content),
                                      content_type='application/json')
                self.assert200(rv)
                self.assertEqual(content['content'], rv.json['content'])
                self.assertFalse(rv.json['draft'])

                self.assertEqual(len(outbox), 0)

        # test draft author
        with self.login(self.data.get_extra_student(1).username):
            with mail.record_messages() as outbox:
                draft_content['content'] = 'I am the author'
                rv = self.client.post(draft_url,
                                      data=json.dumps(draft_content),
                                      content_type='application/json')
                self.assert200(rv)
                self.assertEqual(draft_content['content'], rv.json['content'])
                self.assertTrue(rv.json['draft'])

                self.assertEqual(len(outbox), 0)

            # can change draft to False when draft is True
            with mail.record_messages() as outbox:
                draft_content['draft'] = False
                rv = self.client.post(draft_url,
                                      data=json.dumps(draft_content),
                                      content_type='application/json')
                self.assert200(rv)
                self.assertFalse(rv.json['draft'])

                self.assertEqual(len(outbox), 1)
                self.assertEqual(
                    outbox[0].subject,
                    "New Answer Feedback in " + self.data.get_course().name)
                self.assertEqual(
                    outbox[0].recipients,
                    [self.answers[self.assignment.id][0].user.email])

        answer = self.answers[self.assignment.id][0]
        self_evaluation = self.data.create_answer_comment(
            answer.user,
            answer,
            comment_type=AnswerCommentType.self_evaluation,
            draft=True)
        self_evaluation_url = self.get_url(
            course_uuid=self.course.uuid,
            assignment_uuid=self.assignment.uuid,
            answer_uuid=answer.uuid,
            answer_comment_uuid=self_evaluation.uuid)

        with self.login(answer.user.username):
            lti_consumer = self.lti_data.lti_consumer
            (lti_user_resource_link1, lti_user_resource_link2
             ) = self.lti_data.setup_student_user_resource_links(
                 answer.user, self.course, self.assignment)

            course_grade = CourseGrade.get_user_course_grade(
                self.course, answer.user).grade
            assignment_grade = AssignmentGrade.get_user_assignment_grade(
                self.assignment, answer.user).grade
            content = {
                'id': self_evaluation.uuid,
                'content': 'insightful.',
                'comment_type': AnswerCommentType.self_evaluation.value,
                'draft': True
            }

            with mail.record_messages() as outbox:
                rv = self.client.post(self_evaluation_url,
                                      data=json.dumps(content),
                                      content_type='application/json')
                self.assert200(rv)
                self.assertEqual(content['content'], rv.json['content'])
                self.assertTrue(rv.json['draft'])

                self.assertEqual(len(outbox), 0)

                # grades should not change
                new_course_grade = CourseGrade.get_user_course_grade(
                    self.course, answer.user).grade
                new_assignment_grade = AssignmentGrade.get_user_assignment_grade(
                    self.assignment, answer.user).grade
                self.assertEqual(new_course_grade, course_grade)
                self.assertEqual(new_assignment_grade, assignment_grade)

            # can change draft to False when draft is True
            with mail.record_messages() as outbox:
                content['draft'] = False
                rv = self.client.post(self_evaluation_url,
                                      data=json.dumps(content),
                                      content_type='application/json')
                self.assert200(rv)
                self.assertFalse(rv.json['draft'])

                self.assertEqual(len(outbox), 0)

                # grades should increase
                new_course_grade = CourseGrade.get_user_course_grade(
                    self.course, answer.user)
                new_assignment_grade = AssignmentGrade.get_user_assignment_grade(
                    self.assignment, answer.user)
                self.assertGreater(new_course_grade.grade, course_grade)
                self.assertGreater(new_assignment_grade.grade,
                                   assignment_grade)

                mocked_update_assignment_grades_run.assert_called_once_with(
                    lti_consumer.id,
                    [(lti_user_resource_link2.lis_result_sourcedid,
                      new_assignment_grade.id)])
                mocked_update_assignment_grades_run.reset_mock()

                mocked_update_course_grades_run.assert_called_once_with(
                    lti_consumer.id,
                    [(lti_user_resource_link1.lis_result_sourcedid,
                      new_course_grade.id)])
                mocked_update_course_grades_run.reset_mock()
Beispiel #10
0
    def test_create_answer_comment(self, mocked_update_assignment_grades_run,
                                   mocked_update_course_grades_run):
        url = self.get_url(
            course_uuid=self.course.uuid,
            assignment_uuid=self.assignment.uuid,
            answer_uuid=self.answers[self.assignment.id][0].uuid)
        content = {
            'comment_type': AnswerCommentType.private.value,
            'content': 'great answer'
        }

        # test login required
        rv = self.client.post(url,
                              data=json.dumps(content),
                              content_type='application/json')
        self.assert401(rv)

        # test unauthorized user
        with self.login(self.data.get_unauthorized_instructor().username):
            rv = self.client.post(url,
                                  data=json.dumps(content),
                                  content_type='application/json')
            self.assert403(rv)

        # test invalid course id
        with self.login(self.data.get_authorized_instructor().username):
            invalid_url = self.get_url(
                course_uuid="999",
                assignment_uuid=self.assignment.uuid,
                answer_uuid=self.answers[self.assignment.id][0].uuid)
            rv = self.client.post(invalid_url,
                                  data=json.dumps(content),
                                  content_type='application/json')
            self.assert404(rv)

            # test invalid assignment id
            invalid_url = self.get_url(
                course_uuid=self.course.uuid,
                assignment_uuid="999",
                answer_uuid=self.answers[self.assignment.id][0].uuid)
            rv = self.client.post(invalid_url,
                                  data=json.dumps(content),
                                  content_type='application/json')
            self.assert404(rv)

            # test invalid answer id
            invalid_url = self.get_url(course_uuid=self.course.uuid,
                                       assignment_uuid=self.assignment.uuid,
                                       answer_uuid="999")
            rv = self.client.post(invalid_url,
                                  data=json.dumps(content),
                                  content_type='application/json')
            self.assert404(rv)

            # test empty content
            empty = content.copy()
            empty['content'] = ''
            rv = self.client.post(url,
                                  data=json.dumps(empty),
                                  content_type='application/json')
            self.assert400(rv)

            # test empty comment type
            empty = content.copy()
            empty['comment_type'] = ''
            rv = self.client.post(url,
                                  data=json.dumps(empty),
                                  content_type='application/json')
            self.assert400(rv)

            # test authorized user
            with mail.record_messages() as outbox:
                rv = self.client.post(url,
                                      data=json.dumps(content),
                                      content_type='application/json')
                self.assert200(rv)
                self.assertEqual(content['content'], rv.json['content'])
                self.assertFalse(rv.json['draft'])

                self.assertEqual(len(outbox), 1)
                self.assertEqual(
                    outbox[0].subject,
                    "New Answer Feedback in " + self.data.get_course().name)
                self.assertEqual(
                    outbox[0].recipients,
                    [self.answers[self.assignment.id][0].user.email])

            # test authorized user draft
            with mail.record_messages() as outbox:
                draft_content = content.copy()
                draft_content['draft'] = True
                rv = self.client.post(url,
                                      data=json.dumps(draft_content),
                                      content_type='application/json')
                self.assert200(rv)
                self.assertEqual(content['content'], rv.json['content'])
                self.assertTrue(rv.json['draft'])

                self.assertEqual(len(outbox), 0)

            # test authorized user draft - empty content
            with mail.record_messages() as outbox:
                empty = draft_content.copy()
                empty['content'] = None
                rv = self.client.post(url,
                                      data=json.dumps(empty),
                                      content_type='application/json')
                self.assert200(rv)
                self.assertEqual(empty['content'], rv.json['content'])
                self.assertTrue(rv.json['draft'])

                self.assertEqual(len(outbox), 0)

        with self.login('root'):
            with mail.record_messages() as outbox:
                rv = self.client.post(url,
                                      data=json.dumps(content),
                                      content_type='application/json')
                self.assert200(rv)
                self.assertEqual(len(outbox), 1)

        with self.login(self.data.get_authorized_student().username):
            lti_consumer = self.lti_data.lti_consumer
            (lti_user_resource_link1, lti_user_resource_link2
             ) = self.lti_data.setup_student_user_resource_links(
                 self.data.get_authorized_student(), self.course,
                 self.assignment)

            course_grade = CourseGrade.get_user_course_grade(
                self.course, self.data.get_authorized_student()).grade
            assignment_grade = AssignmentGrade.get_user_assignment_grade(
                self.assignment, self.data.get_authorized_student()).grade

            content = {
                'comment_type': AnswerCommentType.self_evaluation.value,
                'content': 'great answer'
            }

            with mail.record_messages() as outbox:
                rv = self.client.post(url,
                                      data=json.dumps(content),
                                      content_type='application/json')
                self.assert200(rv)

                self.assertEqual(len(outbox), 0)

                # grades should increase
                new_course_grade = CourseGrade.get_user_course_grade(
                    self.course, self.data.get_authorized_student())
                new_assignment_grade = AssignmentGrade.get_user_assignment_grade(
                    self.assignment, self.data.get_authorized_student())
                self.assertGreater(new_course_grade.grade, course_grade)
                self.assertGreater(new_assignment_grade.grade,
                                   assignment_grade)

                mocked_update_assignment_grades_run.assert_called_once_with(
                    lti_consumer.id,
                    [(lti_user_resource_link2.lis_result_sourcedid,
                      new_assignment_grade.id)])
                mocked_update_assignment_grades_run.reset_mock()

                mocked_update_course_grades_run.assert_called_once_with(
                    lti_consumer.id,
                    [(lti_user_resource_link1.lis_result_sourcedid,
                      new_course_grade.id)])
                mocked_update_assignment_grades_run.reset_mock()
Beispiel #11
0
    def test_edit_answer_comment(self, mocked_update_assignment_grades_run, mocked_update_course_grades_run):
        comment = self.data.get_answer_comments_by_assignment(self.assignment)[0]
        url = self.get_url(
            course_uuid=self.course.uuid, assignment_uuid=self.assignment.uuid,
            answer_uuid=self.answers[self.assignment.id][0].uuid, answer_comment_uuid=comment.uuid
        )

        content = {
            'id': comment.uuid,
            'content': 'insightful.',
            'comment_type': AnswerCommentType.private.value
        }
        draft_comment = self.data.get_answer_comments_by_assignment(self.assignment)[2]
        draft_url = self.get_url(
            course_uuid=self.course.uuid, assignment_uuid=self.assignment.uuid,
            answer_uuid=self.answers[self.assignment.id][0].uuid, answer_comment_uuid=draft_comment.uuid)
        draft_content = {
            'id': draft_comment.uuid,
            'content': 'insightful.',
            'comment_type': AnswerCommentType.private.value,
            'draft': True
        }

        # test login required
        rv = self.client.post(url, data=json.dumps(content), content_type='application/json')
        self.assert401(rv)

        # test unauthorized user
        with self.login(self.data.get_unauthorized_instructor().username):
            rv = self.client.post(url, data=json.dumps(content), content_type='application/json')
            self.assert403(rv)

        # test invalid course id
        with self.login(self.data.get_authorized_instructor().username):
            invalid_url = self.get_url(
                course_uuid="999", assignment_uuid=self.assignment.uuid,
                answer_uuid=self.answers[self.assignment.id][0].uuid, answer_comment_uuid=comment.uuid)
            rv = self.client.post(invalid_url, data=json.dumps(content), content_type='application/json')
            self.assert404(rv)

            # test invalid answer id
            invalid_url = self.get_url(
                course_uuid=self.course.uuid, assignment_uuid=self.assignment.uuid,
                answer_uuid="999", answer_comment_uuid=comment.uuid)
            rv = self.client.post(invalid_url, data=json.dumps(content), content_type='application/json')
            self.assert404(rv)

            # test invalid comment id
            invalid_url = self.get_url(
                course_uuid=self.course.uuid, assignment_uuid=self.assignment.uuid,
                answer_uuid=self.answers[self.assignment.id][0].uuid, answer_comment_uuid="999")
            rv = self.client.post(invalid_url, data=json.dumps(content), content_type='application/json')
            self.assert404(rv)

            # test unmatched comment ids
            invalid = content.copy()
            invalid['id'] = self.data.get_answer_comments_by_assignment(self.assignment)[1].uuid
            rv = self.client.post(url, data=json.dumps(invalid), content_type='application/json')
            self.assert400(rv)
            self.assertEqual("Feedback Not Saved", rv.json['title'])
            self.assertEqual("The feedback's ID does not match the URL, which is required in order to save the feedback.",
                rv.json['message'])

            # test empty content
            empty = content.copy()
            empty['content'] = ''
            rv = self.client.post(url, data=json.dumps(empty), content_type='application/json')
            self.assert400(rv)
            self.assertEqual("Feedback Not Saved", rv.json['title'])
            self.assertEqual("Please provide content in the text editor and try saving again.", rv.json['message'])

            # test empty comment_type
            empty = content.copy()
            empty['comment_type'] = ''
            rv = self.client.post(url, data=json.dumps(empty), content_type='application/json')
            self.assert400(rv)

        # test authorized instructor
        with self.login(self.data.get_authorized_instructor().username):
            with mail.record_messages() as outbox:
                rv = self.client.post(url, data=json.dumps(content), content_type='application/json')
                self.assert200(rv)
                self.assertEqual(content['content'], rv.json['content'])
                self.assertIn('fullname', rv.json['user'])

                self.assertEqual(len(outbox), 0)

        # test author
        with self.login(self.data.get_extra_student(0).username):

            # test student can not change comment to self-eval / eval
            invalid = content.copy()
            invalid['comment_type'] = AnswerCommentType.self_evaluation.value
            rv = self.client.post(url, data=json.dumps(invalid), content_type='application/json')
            self.assert400(rv)
            self.assertEqual("Feedback Not Saved", rv.json['title'])
            self.assertEqual("Feedback type cannot be changed. Please contact support for assistance.", rv.json['message'])

            invalid = content.copy()
            invalid['comment_type'] = AnswerCommentType.evaluation.value
            rv = self.client.post(url, data=json.dumps(invalid), content_type='application/json')
            self.assert400(rv)
            self.assertEqual("Feedback Not Saved", rv.json['title'])
            self.assertEqual("Feedback type cannot be changed. Please contact support for assistance.", rv.json['message'])

            with mail.record_messages() as outbox:
                content['content'] = 'I am the author'
                rv = self.client.post(url, data=json.dumps(content), content_type='application/json')
                self.assert200(rv)
                self.assertEqual(content['content'], rv.json['content'])
                self.assertFalse(rv.json['draft'])
                self.assertNotIn('fullname', rv.json['user'])

                self.assertEqual(len(outbox), 0)

            # ignored setting draft to True when draft is already False
            with mail.record_messages() as outbox:
                content['draft'] = True
                rv = self.client.post(url, data=json.dumps(content), content_type='application/json')
                self.assert200(rv)
                self.assertEqual(content['content'], rv.json['content'])
                self.assertFalse(rv.json['draft'])
                self.assertNotIn('fullname', rv.json['user'])

                self.assertEqual(len(outbox), 0)

        # test author with impersonation
        student = self.data.get_extra_student(0)
        with self.impersonate(self.data.get_authorized_instructor(), student):
            content['content'] = 'I am the author'
            rv = self.client.post(url, data=json.dumps(content), content_type='application/json')
            self.assert403(rv)
            self.assertTrue(rv.json['disabled_by_impersonation'])

            content['draft'] = True
            rv = self.client.post(url, data=json.dumps(content), content_type='application/json')
            self.assert403(rv)
            self.assertTrue(rv.json['disabled_by_impersonation'])

        # test draft author
        with self.login(self.data.get_extra_student(1).username):
            with mail.record_messages() as outbox:
                draft_content['content'] = 'I am the author'
                rv = self.client.post(draft_url, data=json.dumps(draft_content), content_type='application/json')
                self.assert200(rv)
                self.assertEqual(draft_content['content'], rv.json['content'])
                self.assertTrue(rv.json['draft'])
                self.assertNotIn('fullname', rv.json['user'])

                self.assertEqual(len(outbox), 0)

            # can change draft to False when draft is True
            with mail.record_messages() as outbox:
                draft_content['draft'] = False
                rv = self.client.post(draft_url, data=json.dumps(draft_content), content_type='application/json')
                self.assert200(rv)
                self.assertFalse(rv.json['draft'])
                self.assertNotIn('fullname', rv.json['user'])

                self.assertEqual(len(outbox), 1)
                self.assertEqual(outbox[0].subject, "New Answer Feedback in "+self.data.get_course().name)
                self.assertEqual(outbox[0].recipients, [self.answers[self.assignment.id][0].user.email])

        # test draft author with impersonation
        student = self.data.get_extra_student(1)
        with self.impersonate(self.data.get_authorized_instructor(), student):
            draft_content['content'] = 'I am the author'
            rv = self.client.post(draft_url, data=json.dumps(draft_content), content_type='application/json')
            self.assert403(rv)
            self.assertTrue(rv.json['disabled_by_impersonation'])

            # cant change draft to False
            draft_content['draft'] = False
            rv = self.client.post(draft_url, data=json.dumps(draft_content), content_type='application/json')
            self.assert403(rv)
            self.assertTrue(rv.json['disabled_by_impersonation'])

        answer = self.answers[self.assignment.id][0]
        self_evaluation = self.data.create_answer_comment(
            answer.user, answer, comment_type=AnswerCommentType.self_evaluation, draft=True)
        self_evaluation_url = self.get_url(
            course_uuid=self.course.uuid, assignment_uuid=self.assignment.uuid,
            answer_uuid=answer.uuid, answer_comment_uuid=self_evaluation.uuid)

        with self.login(answer.user.username):
            lti_consumer = self.lti_data.lti_consumer
            (lti_user_resource_link1, lti_user_resource_link2) = self.lti_data.setup_student_user_resource_links(
                answer.user, self.course, self.assignment)

            course_grade = CourseGrade.get_user_course_grade(self.course, answer.user).grade
            assignment_grade = AssignmentGrade.get_user_assignment_grade(self.assignment, answer.user).grade
            content = {
                'id': self_evaluation.uuid,
                'content': 'insightful.',
                'comment_type': AnswerCommentType.self_evaluation.value,
                'draft': True
            }

            # test student can not submit self-eval after self-eval grace period
            orig_answer_end = self.assignment.answer_end
            self.assignment.answer_end = datetime.datetime.utcnow() - datetime.timedelta(hours=12)
            self.assignment.self_eval_start = datetime.datetime.utcnow() - datetime.timedelta(hours=1)
            self.assignment.self_eval_end = datetime.datetime.utcnow() - datetime.timedelta(minutes=10)

            db.session.add(self.assignment)
            db.session.commit()

            rv = self.client.post(self_evaluation_url, data=json.dumps(content), content_type='application/json')
            self.assert403(rv)
            self.assertEqual("Self-Evaluation Not Saved", rv.json['title'])
            self.assertEqual("Sorry, the self-evaluation deadline has passed and therefore cannot be submitted.",
                rv.json['message'])

            self.assignment.answer_end = orig_answer_end
            self.assignment.self_eval_start = None
            self.assignment.self_eval_end = None


            with mail.record_messages() as outbox:
                self.assignment.answer_end = datetime.datetime.utcnow() - datetime.timedelta(hours=12)
                rv = self.client.post(self_evaluation_url, data=json.dumps(content), content_type='application/json')
                self.assert200(rv)
                self.assertEqual(content['content'], rv.json['content'])
                self.assertTrue(rv.json['draft'])
                self.assertNotIn('fullname', rv.json['user'])

                self.assertEqual(len(outbox), 0)

                # grades should not change
                new_course_grade = CourseGrade.get_user_course_grade(self.course, answer.user).grade
                new_assignment_grade = AssignmentGrade.get_user_assignment_grade(self.assignment, answer.user).grade
                self.assertEqual(new_course_grade, course_grade)
                self.assertEqual(new_assignment_grade, assignment_grade)

            # can change draft to False when draft is True
            with mail.record_messages() as outbox:
                content['draft'] = False
                rv = self.client.post(self_evaluation_url, data=json.dumps(content), content_type='application/json')
                self.assert200(rv)
                self.assertFalse(rv.json['draft'])
                self.assertNotIn('fullname', rv.json['user'])

                self.assertEqual(len(outbox), 0)

                # grades should increase
                new_course_grade = CourseGrade.get_user_course_grade(self.course, answer.user)
                new_assignment_grade = AssignmentGrade.get_user_assignment_grade(self.assignment, answer.user)
                self.assertGreater(new_course_grade.grade, course_grade)
                self.assertGreater(new_assignment_grade.grade, assignment_grade)

                mocked_update_assignment_grades_run.assert_called_once_with(
                    lti_consumer.id,
                    [(lti_user_resource_link2.lis_result_sourcedid, new_assignment_grade.id)]
                )
                mocked_update_assignment_grades_run.reset_mock()

                mocked_update_course_grades_run.assert_called_once_with(
                    lti_consumer.id,
                    [(lti_user_resource_link1.lis_result_sourcedid, new_course_grade.id)]
                )
                mocked_update_course_grades_run.reset_mock()

        # test self-evaluation with impersonation
        answers = self.answers[self.assignment.id]
        for answer in [a for a in answers if a.user.system_role == SystemRole.student]:
            self_evaluation = self.data.create_answer_comment(
                answer.user, answer, comment_type=AnswerCommentType.self_evaluation, draft=True)
            self_evaluation_url = self.get_url(
                course_uuid=self.course.uuid, assignment_uuid=self.assignment.uuid,
                answer_uuid=answer.uuid, answer_comment_uuid=self_evaluation.uuid)

            with self.impersonate(self.data.get_authorized_instructor(), answer.user):
                content = {
                    'id': self_evaluation.uuid,
                    'content': 'insightful.',
                    'comment_type': AnswerCommentType.self_evaluation.value,
                    'draft': True
                }

                rv = self.client.post(self_evaluation_url, data=json.dumps(content), content_type='application/json')
                self.assert403(rv)
                self.assertTrue(rv.json['disabled_by_impersonation'])
                # attempt to change draft to False
                content['draft'] = False
                rv = self.client.post(self_evaluation_url, data=json.dumps(content), content_type='application/json')
                self.assert403(rv)
                self.assertTrue(rv.json['disabled_by_impersonation'])
Beispiel #12
0
    def test_create_answer_comment(self, mocked_update_assignment_grades_run, mocked_update_course_grades_run):
        url = self.get_url(
            course_uuid=self.course.uuid, assignment_uuid=self.assignment.uuid,
            answer_uuid=self.answers[self.assignment.id][0].uuid)
        content = {
            'comment_type': AnswerCommentType.private.value,
            'content': 'great answer'
        }

        # test login required
        rv = self.client.post(url, data=json.dumps(content), content_type='application/json')
        self.assert401(rv)

        # test unauthorized user
        with self.login(self.data.get_unauthorized_instructor().username):
            rv = self.client.post(url, data=json.dumps(content), content_type='application/json')
            self.assert403(rv)

        # test invalid course id
        with self.login(self.data.get_authorized_instructor().username):
            invalid_url = self.get_url(
                course_uuid="999", assignment_uuid=self.assignment.uuid,
                answer_uuid=self.answers[self.assignment.id][0].uuid)
            rv = self.client.post(invalid_url, data=json.dumps(content), content_type='application/json')
            self.assert404(rv)

            # test invalid assignment id
            invalid_url = self.get_url(
                course_uuid=self.course.uuid, assignment_uuid="999",
                answer_uuid=self.answers[self.assignment.id][0].uuid)
            rv = self.client.post(invalid_url, data=json.dumps(content), content_type='application/json')
            self.assert404(rv)

            # test invalid answer id
            invalid_url = self.get_url(
                course_uuid=self.course.uuid, assignment_uuid=self.assignment.uuid, answer_uuid="999")
            rv = self.client.post(invalid_url, data=json.dumps(content), content_type='application/json')
            self.assert404(rv)

            # test empty content
            empty = content.copy()
            empty['content'] = ''
            rv = self.client.post(url, data=json.dumps(empty), content_type='application/json')
            self.assert400(rv)

            # test empty comment type
            empty = content.copy()
            empty['comment_type'] = ''
            rv = self.client.post(url, data=json.dumps(empty), content_type='application/json')
            self.assert400(rv)

            # test authorized user
            with mail.record_messages() as outbox:
                rv = self.client.post(url, data=json.dumps(content), content_type='application/json')
                self.assert200(rv)
                self.assertEqual(content['content'], rv.json['content'])
                self.assertFalse(rv.json['draft'])
                self.assertIn('fullname', rv.json['user'])

                self.assertEqual(len(outbox), 1)
                self.assertEqual(outbox[0].subject, "New Answer Feedback in "+self.data.get_course().name)
                self.assertEqual(outbox[0].recipients, [self.answers[self.assignment.id][0].user.email])

            # test authorized user draft
            with mail.record_messages() as outbox:
                draft_content = content.copy()
                draft_content['draft'] = True
                rv = self.client.post(url, data=json.dumps(draft_content), content_type='application/json')
                self.assert200(rv)
                self.assertEqual(content['content'], rv.json['content'])
                self.assertTrue(rv.json['draft'])

                self.assertEqual(len(outbox), 0)

            # test authorized user draft - empty content
            with mail.record_messages() as outbox:
                empty = draft_content.copy()
                empty['content'] = None
                rv = self.client.post(url, data=json.dumps(empty), content_type='application/json')
                self.assert200(rv)
                self.assertEqual(empty['content'], rv.json['content'])
                self.assertTrue(rv.json['draft'])

                self.assertEqual(len(outbox), 0)

        with self.login('root'):
            with mail.record_messages() as outbox:
                rv = self.client.post(url, data=json.dumps(content), content_type='application/json')
                self.assert200(rv)
                self.assertEqual(len(outbox), 1)
                self.assertIn('fullname', rv.json['user'])

        with self.login(self.data.get_authorized_student().username):
            lti_consumer = self.lti_data.lti_consumer
            (lti_user_resource_link1, lti_user_resource_link2) = self.lti_data.setup_student_user_resource_links(
                self.data.get_authorized_student(), self.course, self.assignment)

            course_grade = CourseGrade.get_user_course_grade(self.course, self.data.get_authorized_student()).grade
            assignment_grade = AssignmentGrade.get_user_assignment_grade(self.assignment, self.data.get_authorized_student()).grade

            content = {
                'comment_type': AnswerCommentType.self_evaluation.value,
                'content': 'great answer'
            }

            # test student can not submit self-eval after self-eval grace period
            orig_answer_end = self.assignment.answer_end
            self.assignment.answer_end = datetime.datetime.utcnow() - datetime.timedelta(hours=12)
            self.assignment.self_eval_start = datetime.datetime.utcnow() - datetime.timedelta(hours=1)
            self.assignment.self_eval_end = datetime.datetime.utcnow() - datetime.timedelta(minutes=10)

            db.session.add(self.assignment)
            db.session.commit()

            rv = self.client.post(url, data=json.dumps(content), content_type='application/json')
            self.assert403(rv)
            self.assertEqual("Self-Evaluation Not Saved", rv.json['title'])
            self.assertEqual("Sorry, the self-evaluation deadline has passed and therefore cannot be submitted.",
                rv.json['message'])

            self.assignment.answer_end = orig_answer_end
            self.assignment.self_eval_start = None
            self.assignment.self_eval_end = None


            with mail.record_messages() as outbox:
                orig_answer_end = self.assignment.answer_end
                self.assignment.answer_end = datetime.datetime.utcnow() - datetime.timedelta(hours=12)

                rv = self.client.post(url, data=json.dumps(content), content_type='application/json')
                self.assert200(rv)

                self.assertEqual(len(outbox), 0)
                self.assertNotIn('fullname', rv.json['user'])

                # grades should increase
                new_course_grade = CourseGrade.get_user_course_grade(self.course, self.data.get_authorized_student())
                new_assignment_grade = AssignmentGrade.get_user_assignment_grade(self.assignment, self.data.get_authorized_student())
                self.assertGreater(new_course_grade.grade, course_grade)
                self.assertGreater(new_assignment_grade.grade, assignment_grade)

                mocked_update_assignment_grades_run.assert_called_once_with(
                    lti_consumer.id,
                    [(lti_user_resource_link2.lis_result_sourcedid, new_assignment_grade.id)]
                )
                mocked_update_assignment_grades_run.reset_mock()

                mocked_update_course_grades_run.assert_called_once_with(
                    lti_consumer.id,
                    [(lti_user_resource_link1.lis_result_sourcedid, new_course_grade.id)]
                )
                mocked_update_assignment_grades_run.reset_mock()

                self.assignment.answer_end = orig_answer_end

        # test with impersonation
        student = self.data.get_extra_student(0)
        with self.impersonate(self.data.get_authorized_instructor(), student):
            lti_consumer = self.lti_data.lti_consumer
            (lti_user_resource_link1, lti_user_resource_link2) = self.lti_data.setup_student_user_resource_links(
                self.data.get_authorized_student(), self.course, self.assignment)

            course_grade = CourseGrade.get_user_course_grade(self.course, self.data.get_authorized_student()).grade
            assignment_grade = AssignmentGrade.get_user_assignment_grade(self.assignment, self.data.get_authorized_student()).grade

            content = {
                'comment_type': AnswerCommentType.self_evaluation.value,
                'content': 'great answer'
            }

            with mail.record_messages() as outbox:
                rv = self.client.post(url, data=json.dumps(content), content_type='application/json')
                self.assert403(rv)
                self.assertTrue(rv.json['disabled_by_impersonation'])
Beispiel #13
0
    def test_edit_answer(self, mocked_update_assignment_grades_run, mocked_update_course_grades_run):
        assignment_uuid = self.fixtures.assignments[0].uuid
        answer = self.fixtures.answers[0]
        expected = {'id': answer.uuid, 'content': 'This is an edit'}
        draft_answer = self.fixtures.draft_answers[0]
        draft_expected = {'id': draft_answer.uuid, 'content': 'This is an edit', 'draft': True}

        # test login required
        rv = self.client.post(
            self.base_url + '/' + answer.uuid,
            data=json.dumps(expected),
            content_type='application/json')
        self.assert401(rv)

        # test unauthorized user
        with self.login(self.fixtures.students[1].username):
            rv = self.client.post(
                self.base_url + '/' + answer.uuid,
                data=json.dumps(expected),
                content_type='application/json')
            self.assert403(rv)

        # test invalid course id
        with self.login(self.fixtures.students[0].username):
            rv = self.client.post(
                self._build_url("999", assignment_uuid, '/' + answer.uuid),
                data=json.dumps(expected),
                content_type='application/json')
            self.assert404(rv)

            # test invalid assignment id
            rv = self.client.post(
                self._build_url(self.fixtures.course.uuid, "999", '/' + answer.uuid),
                data=json.dumps(expected),
                content_type='application/json')
            self.assert404(rv)

            # test invalid answer id
            rv = self.client.post(
                self.base_url + '/999',
                data=json.dumps(expected),
                content_type='application/json')
            self.assert404(rv)

        # test unmatched answer id
        with self.login(self.fixtures.students[1].username):
            rv = self.client.post(
                self.base_url + '/' + self.fixtures.answers[1].uuid,
                data=json.dumps(expected),
                content_type='application/json')
            self.assert400(rv)

        with self.login(self.fixtures.draft_student.username):
            course_grade = CourseGrade.get_user_course_grade(
                self.fixtures.course, self.fixtures.draft_student).grade
            assignment_grade = AssignmentGrade.get_user_assignment_grade(
                self.fixtures.assignments[0], self.fixtures.draft_student).grade

            lti_consumer = self.lti_data.lti_consumer
            student = self.fixtures.draft_student
            (lti_user_resource_link1, lti_user_resource_link2) = self.lti_data.setup_student_user_resource_links(
                student, self.fixtures.course, self.fixtures.assignment)

            # test edit draft by author
            rv = self.client.post(
                self.base_url + '/' + draft_answer.uuid,
                data=json.dumps(draft_expected),
                content_type='application/json')
            self.assert200(rv)
            self.assertEqual(draft_answer.uuid, rv.json['id'])
            self.assertEqual('This is an edit', rv.json['content'])
            self.assertEqual(draft_answer.draft, rv.json['draft'])
            self.assertTrue(rv.json['draft'])

            # grades should not change
            new_course_grade = CourseGrade.get_user_course_grade(
                self.fixtures.course, self.fixtures.draft_student).grade
            new_assignment_grade = AssignmentGrade.get_user_assignment_grade(
                self.fixtures.assignments[0], self.fixtures.draft_student).grade
            self.assertEqual(new_course_grade, course_grade)
            self.assertEqual(new_assignment_grade, assignment_grade)

            mocked_update_assignment_grades_run.assert_not_called()
            mocked_update_course_grades_run.assert_not_called()

            # set draft to false
            draft_expected_copy = draft_expected.copy()
            draft_expected_copy['draft'] = False
            rv = self.client.post(
                self.base_url + '/' + draft_answer.uuid,
                data=json.dumps(draft_expected_copy),
                content_type='application/json')
            self.assert200(rv)
            self.assertEqual(draft_answer.uuid, rv.json['id'])
            self.assertEqual('This is an edit', rv.json['content'])
            self.assertEqual(draft_answer.draft, rv.json['draft'])
            self.assertFalse(rv.json['draft'])

            # grades should increase
            new_course_grade = CourseGrade.get_user_course_grade(
                self.fixtures.course, self.fixtures.draft_student)
            new_assignment_grade = AssignmentGrade.get_user_assignment_grade(
                self.fixtures.assignments[0], self.fixtures.draft_student)
            self.assertGreater(new_course_grade.grade, course_grade)
            self.assertGreater(new_assignment_grade.grade, assignment_grade)

            mocked_update_assignment_grades_run.assert_called_once_with(
                lti_consumer.id,
                [(lti_user_resource_link2.lis_result_sourcedid, new_assignment_grade.id)]
            )
            mocked_update_assignment_grades_run.reset_mock()

            mocked_update_course_grades_run.assert_called_once_with(
                lti_consumer.id,
                [(lti_user_resource_link1.lis_result_sourcedid, new_course_grade.id)]
            )
            mocked_update_course_grades_run.reset_mock()

            # setting draft to true when false should not work
            rv = self.client.post(
                self.base_url + '/' + draft_answer.uuid,
                data=json.dumps(draft_expected),
                content_type='application/json')
            self.assert200(rv)
            self.assertEqual(draft_answer.uuid, rv.json['id'])
            self.assertEqual('This is an edit', rv.json['content'])
            self.assertEqual(draft_answer.draft, rv.json['draft'])
            self.assertFalse(rv.json['draft'])

        # test edit by author
        with self.login(self.fixtures.students[0].username):
            rv = self.client.post(
                self.base_url + '/' + answer.uuid,
                data=json.dumps(expected),
                content_type='application/json')
            self.assert200(rv)
            self.assertEqual(answer.uuid, rv.json['id'])
            self.assertEqual('This is an edit', rv.json['content'])

        # test edit by user that can manage posts
        manage_expected = {
            'id': answer.uuid,
            'content': 'This is another edit'
        }
        with self.login(self.fixtures.instructor.username):
            rv = self.client.post(
                self.base_url + '/' + answer.uuid,
                data=json.dumps(manage_expected),
                content_type='application/json')
            self.assert200(rv)
            self.assertEqual(answer.uuid, rv.json['id'])
            self.assertEqual('This is another edit', rv.json['content'])

        # test edit by author
        with self.login(self.fixtures.students[0].username):
            # test student can not submit answers after answer grace period
            self.fixtures.assignment.answer_end = datetime.datetime.utcnow() - datetime.timedelta(minutes=10)
            db.session.add(self.fixtures.assignment)
            db.session.commit()

            rv = self.client.post(
                self.base_url + '/' + answer.uuid,
                data=json.dumps(expected),
                content_type='application/json')
            self.assert403(rv)
            self.assertEqual("Answer Not Submitted", rv.json['title'])
            self.assertEqual("Sorry, the answer deadline has passed. No answers can be submitted after the deadline unless the instructor submits the answer for you.",
                rv.json['message'])

            # test student can submit answers within answer grace period
            self.fixtures.assignment.answer_end = datetime.datetime.utcnow() - datetime.timedelta(seconds=15)
            db.session.add(self.fixtures.assignment)
            db.session.commit()

            rv = self.client.post(
                self.base_url + '/' + answer.uuid,
                data=json.dumps(expected),
                content_type='application/json')
            self.assert200(rv)
            self.assertEqual(answer.uuid, rv.json['id'])
            self.assertEqual('This is an edit', rv.json['content'])
Beispiel #14
0
    def test_create_answer(self, mocked_update_assignment_grades_run, mocked_update_course_grades_run):
        # test login required
        expected_answer = {'content': 'this is some answer content'}
        rv = self.client.post(
            self.base_url,
            data=json.dumps(expected_answer),
            content_type='application/json')
        self.assert401(rv)
        # test unauthorized users
        with self.login(self.fixtures.unauthorized_student.username):
            rv = self.client.post(self.base_url, data=json.dumps(expected_answer),
                                        content_type='application/json')
            self.assert403(rv)
        with self.login(self.fixtures.unauthorized_instructor.username):
            rv = self.client.post(
                self.base_url,
                data=json.dumps(expected_answer),
                content_type='application/json')
            self.assert403(rv)

        # test invalid format
        with self.login(self.fixtures.students[0].username):
            invalid_answer = {'post': {'blah': 'blah'}}
            rv = self.client.post(
                self.base_url,
                data=json.dumps(invalid_answer),
                content_type='application/json')
            self.assert400(rv)
            # test invalid assignment
            rv = self.client.post(
                self._build_url(self.fixtures.course.uuid, "9392402"),
                data=json.dumps(expected_answer),
                content_type='application/json')
            self.assert404(rv)
            # test invalid course
            rv = self.client.post(
                self._build_url("9392402", self.fixtures.assignment.uuid),
                data=json.dumps(expected_answer), content_type='application/json')
            self.assert404(rv)

        # test create successful
        with self.login(self.fixtures.instructor.username):
            rv = self.client.post(
                self.base_url,
                data=json.dumps(expected_answer),
                content_type='application/json')
            self.assert200(rv)
            # retrieve again and verify
            actual_answer = Answer.query.filter_by(uuid=rv.json['id']).one()
            self.assertEqual(expected_answer['content'], actual_answer.content)

            # user should not have grades
            new_course_grade = CourseGrade.get_user_course_grade( self.fixtures.course, self.fixtures.instructor)
            new_assignment_grade = AssignmentGrade.get_user_assignment_grade(self.fixtures.assignment, self.fixtures.instructor)
            self.assertIsNone(new_course_grade)
            self.assertIsNone(new_assignment_grade)

            # test instructor could submit multiple answers for his/her own
            rv = self.client.post(
                self.base_url,
                data=json.dumps(expected_answer),
                content_type='application/json')
            self.assert200(rv)
            actual_answer = Answer.query.filter_by(uuid=rv.json['id']).one()
            self.assertEqual(expected_answer['content'], actual_answer.content)

            # user should not have grades
            new_course_grade = CourseGrade.get_user_course_grade( self.fixtures.course, self.fixtures.instructor)
            new_assignment_grade = AssignmentGrade.get_user_assignment_grade(self.fixtures.assignment, self.fixtures.instructor)
            self.assertIsNone(new_course_grade)
            self.assertIsNone(new_assignment_grade)

            # test instructor could submit multiple answers for his/her own
            expected_answer.update({'user_id': self.fixtures.instructor.uuid})
            rv = self.client.post(
                self.base_url,
                data=json.dumps(expected_answer),
                content_type='application/json')
            self.assert200(rv)
            actual_answer = Answer.query.filter_by(uuid=rv.json['id']).one()
            self.assertEqual(expected_answer['content'], actual_answer.content)

            # user should not have grades
            new_course_grade = CourseGrade.get_user_course_grade( self.fixtures.course, self.fixtures.instructor)
            new_assignment_grade = AssignmentGrade.get_user_assignment_grade(self.fixtures.assignment, self.fixtures.instructor)
            self.assertIsNone(new_course_grade)
            self.assertIsNone(new_assignment_grade)

            # test instructor could submit on behave of a student
            self.fixtures.add_students(1)
            expected_answer.update({'user_id': self.fixtures.students[-1].uuid})
            rv = self.client.post(
                self.base_url,
                data=json.dumps(expected_answer),
                content_type='application/json')
            self.assert200(rv)
            actual_answer = Answer.query.filter_by(uuid=rv.json['id']).one()
            self.assertEqual(expected_answer['content'], actual_answer.content)

            # user should have grades
            new_course_grade = CourseGrade.get_user_course_grade( self.fixtures.course, self.fixtures.students[-1])
            new_assignment_grade = AssignmentGrade.get_user_assignment_grade(self.fixtures.assignment, self.fixtures.students[-1])
            self.assertIsNotNone(new_course_grade)
            self.assertIsNotNone(new_assignment_grade)

            # test instructor can not submit additional answers for a student
            expected_answer.update({'user_id': self.fixtures.students[0].uuid})
            rv = self.client.post(
                self.base_url,
                data=json.dumps(expected_answer),
                content_type='application/json')
            self.assert400(rv)
            self.assertEqual(rv.json['title'], "Answer Not Submitted")
            self.assertEqual(rv.json['message'], "An answer has already been submitted for this assignment by you or on your behalf.")

        self.fixtures.add_students(1)
        self.fixtures.course.calculate_grade(self.fixtures.students[-1])
        self.fixtures.assignment.calculate_grade(self.fixtures.students[-1])
        expected_answer = {'content': 'this is some answer content', 'draft': True}
        with self.login(self.fixtures.students[-1].username):
            course_grade = CourseGrade.get_user_course_grade(
                self.fixtures.course, self.fixtures.students[-1]).grade
            assignment_grade = AssignmentGrade.get_user_assignment_grade(
                self.fixtures.assignments[0], self.fixtures.students[-1]).grade

            # test create draft successful
            rv = self.client.post(
                self.base_url,
                data=json.dumps(expected_answer),
                content_type='application/json')
            self.assert200(rv)
            actual_answer = Answer.query.filter_by(uuid=rv.json['id']).one()
            self.assertEqual(expected_answer['content'], actual_answer.content)
            self.assertEqual(expected_answer['draft'], actual_answer.draft)

            # grades should not change
            new_course_grade = CourseGrade.get_user_course_grade(
                self.fixtures.course, self.fixtures.draft_student).grade
            new_assignment_grade = AssignmentGrade.get_user_assignment_grade(
                self.fixtures.assignments[0], self.fixtures.draft_student).grade
            self.assertEqual(new_course_grade, course_grade)
            self.assertEqual(new_assignment_grade, assignment_grade)

        with self.login(self.fixtures.instructor.username):
            # test instructor can submit outside of grace period
            self.fixtures.assignment.answer_end = datetime.datetime.utcnow() - datetime.timedelta(minutes=2)
            db.session.add(self.fixtures.assignment)
            db.session.commit()

            self.fixtures.add_students(1)
            expected_answer.update({'user_id': self.fixtures.students[-1].uuid})
            rv = self.client.post(
                self.base_url,
                data=json.dumps(expected_answer),
                content_type='application/json')
            self.assert200(rv)
            actual_answer = Answer.query.filter_by(uuid=rv.json['id']).one()
            self.assertEqual(expected_answer['content'], actual_answer.content)

        # test create successful
        self.fixtures.add_students(1)
        self.fixtures.course.calculate_grade(self.fixtures.students[-1])
        self.fixtures.assignment.calculate_grade(self.fixtures.students[-1])
        expected_answer = {'content': 'this is some answer content'}
        with self.login(self.fixtures.students[-1].username):
            # test student can not submit answers after answer grace period
            self.fixtures.assignment.answer_end = datetime.datetime.utcnow() - datetime.timedelta(minutes=2)
            db.session.add(self.fixtures.assignment)
            db.session.commit()

            rv = self.client.post(
                self.base_url,
                data=json.dumps(expected_answer),
                content_type='application/json')
            self.assert403(rv)
            self.assertEqual("Answer Not Submitted", rv.json['title'])
            self.assertEqual("Sorry, the answer deadline has passed. No answers can be submitted after the deadline unless the instructor submits the answer for you.",
                rv.json['message'])

            # test student can submit answers within answer grace period
            self.fixtures.assignment.answer_end = datetime.datetime.utcnow() - datetime.timedelta(seconds=15)
            db.session.add(self.fixtures.assignment)
            db.session.commit()

            course_grade = CourseGrade.get_user_course_grade(
                self.fixtures.course, self.fixtures.students[-1]).grade
            assignment_grade = AssignmentGrade.get_user_assignment_grade(
                self.fixtures.assignment, self.fixtures.students[-1]).grade

            lti_consumer = self.lti_data.lti_consumer
            student = self.fixtures.students[-1]
            (lti_user_resource_link1, lti_user_resource_link2) = self.lti_data.setup_student_user_resource_links(
                student, self.fixtures.course, self.fixtures.assignment)

            rv = self.client.post(
                self.base_url,
                data=json.dumps(expected_answer),
                content_type='application/json')
            self.assert200(rv)
            actual_answer = Answer.query.filter_by(uuid=rv.json['id']).one()
            self.assertEqual(expected_answer['content'], actual_answer.content)

            # grades should increase
            new_course_grade = CourseGrade.get_user_course_grade(
                self.fixtures.course, self.fixtures.students[-1])
            new_assignment_grade = AssignmentGrade.get_user_assignment_grade(
                self.fixtures.assignment, self.fixtures.students[-1])
            self.assertGreater(new_course_grade.grade, course_grade)
            self.assertGreater(new_assignment_grade.grade, assignment_grade)

            mocked_update_assignment_grades_run.assert_called_once_with(
                lti_consumer.id,
                [(lti_user_resource_link2.lis_result_sourcedid, new_assignment_grade.id)]
            )
            mocked_update_assignment_grades_run.reset_mock()

            mocked_update_course_grades_run.assert_called_once_with(
                lti_consumer.id,
                [(lti_user_resource_link1.lis_result_sourcedid, new_course_grade.id)]
            )
            mocked_update_course_grades_run.reset_mock()

        # test create successful for system admin
        with self.login('root'):
            rv = self.client.post(
                self.base_url,
                data=json.dumps(expected_answer),
                content_type='application/json')
            self.assert200(rv)

            # retrieve again and verify
            actual_answer = Answer.query.filter_by(uuid=rv.json['id']).one()
            self.assertEqual(expected_answer['content'], actual_answer.content)

            # test system admin could submit multiple answers for his/her own
            rv = self.client.post(
                self.base_url,
                data=json.dumps(expected_answer),
                content_type='application/json')
            self.assert200(rv)
            actual_answer = Answer.query.filter_by(uuid=rv.json['id']).one()
            self.assertEqual(expected_answer['content'], actual_answer.content)
Beispiel #15
0
    def test_get_and_submit_comparison(self,
                                       mocked_update_assignment_grades_run,
                                       mocked_update_course_grades_run):
        lti_consumer = self.lti_data.lti_consumer
        (lti_user_resource_link1, lti_user_resource_link2
         ) = self.lti_data.setup_student_user_resource_links(
             self.data.get_authorized_student(), self.course, self.assignment)

        users = [
            self.data.get_authorized_student(),
            self.data.get_authorized_instructor(),
            self.data.get_authorized_ta()
        ]
        for user in users:
            max_comparisons = 0
            other_student_answers = 0
            valid_answer_uuids = set()
            for answer in self.data.get_student_answers():
                if answer.assignment.id == self.assignment.id and answer.user_id != user.id:
                    other_student_answers += 1
                    valid_answer_uuids.add(answer.uuid)
            max_comparisons = int(other_student_answers *
                                  (other_student_answers - 1) / 2)

            if user.id == self.data.get_authorized_student().id:
                for comparison_example in self.data.comparisons_examples:
                    if comparison_example.assignment_id == self.assignment.id:
                        max_comparisons += 1
                        valid_answer_uuids.add(comparison_example.answer1_uuid)
                        valid_answer_uuids.add(comparison_example.answer2_uuid)

            with self.login(user.username):
                if user.id in [
                        self.data.get_authorized_instructor().id,
                        self.data.get_authorized_ta().id
                ]:
                    self.assignment.educators_can_compare = False
                    db.session.commit()

                    # cannot compare answers unless educators_can_compare is set for assignment
                    rv = self.client.get(self.base_url)
                    self.assert403(rv)

                    self.assignment.educators_can_compare = True
                    db.session.commit()

                current = 0
                while current < max_comparisons:
                    current += 1
                    if user.id == self.data.get_authorized_student().id:
                        course_grade = CourseGrade.get_user_course_grade(
                            self.course, user).grade
                        assignment_grade = AssignmentGrade.get_user_assignment_grade(
                            self.assignment, user).grade

                    # establish expected data by first getting an answer pair
                    rv = self.client.get(self.base_url)
                    self.assert200(rv)
                    actual_answer1_uuid = rv.json['comparison']['answer1_id']
                    actual_answer2_uuid = rv.json['comparison']['answer2_id']
                    self.assertIn(actual_answer1_uuid, valid_answer_uuids)
                    self.assertIn(actual_answer2_uuid, valid_answer_uuids)
                    self.assertNotEqual(actual_answer1_uuid,
                                        actual_answer2_uuid)
                    self.assertTrue(rv.json['new_pair'])
                    self.assertEqual(rv.json['current'], current)

                    # fetch again
                    rv = self.client.get(self.base_url)
                    self.assert200(rv)
                    expected_comparison = rv.json['comparison']
                    self.assertEqual(actual_answer1_uuid,
                                     rv.json['comparison']['answer1_id'])
                    self.assertEqual(actual_answer2_uuid,
                                     rv.json['comparison']['answer2_id'])
                    self.assertFalse(rv.json['new_pair'])
                    self.assertEqual(rv.json['current'], current)

                    # test draft post
                    comparison_submit = self._build_comparison_submit(
                        WinningAnswer.answer1.value, True)
                    rv = self.client.post(self.base_url,
                                          data=json.dumps(comparison_submit),
                                          content_type='application/json')
                    self.assert200(rv)
                    actual_comparison = rv.json['comparison']
                    self._validate_comparison_submit(comparison_submit,
                                                     actual_comparison,
                                                     expected_comparison)

                    # test draft post (no winner)
                    comparison_submit = self._build_comparison_submit(None)
                    rv = self.client.post(self.base_url,
                                          data=json.dumps(comparison_submit),
                                          content_type='application/json')
                    self.assert200(rv)
                    actual_comparison = rv.json['comparison']
                    self._validate_comparison_submit(comparison_submit,
                                                     actual_comparison,
                                                     expected_comparison)

                    # test normal post
                    comparison_submit = self._build_comparison_submit(
                        WinningAnswer.answer1.value)
                    rv = self.client.post(self.base_url,
                                          data=json.dumps(comparison_submit),
                                          content_type='application/json')
                    self.assert200(rv)
                    actual_comparison = rv.json['comparison']
                    self._validate_comparison_submit(comparison_submit,
                                                     actual_comparison,
                                                     expected_comparison)

                    # grades should increase for every comparison
                    if user.id == self.data.get_authorized_student().id:
                        new_course_grade = CourseGrade.get_user_course_grade(
                            self.course, user)
                        new_assignment_grade = AssignmentGrade.get_user_assignment_grade(
                            self.assignment, user)
                        self.assertGreater(new_course_grade.grade,
                                           course_grade)
                        self.assertGreater(new_assignment_grade.grade,
                                           assignment_grade)

                        mocked_update_course_grades_run.assert_called_once_with(
                            lti_consumer.id,
                            [(lti_user_resource_link1.lis_result_sourcedid,
                              new_course_grade.id)])
                        mocked_update_course_grades_run.reset_mock()

                        mocked_update_assignment_grades_run.assert_called_once_with(
                            lti_consumer.id,
                            [(lti_user_resource_link2.lis_result_sourcedid,
                              new_assignment_grade.id)])
                        mocked_update_assignment_grades_run.reset_mock()
                    else:
                        new_course_grade = CourseGrade.get_user_course_grade(
                            self.course, user)
                        new_assignment_grade = AssignmentGrade.get_user_assignment_grade(
                            self.assignment, user)
                        self.assertIsNone(new_course_grade)
                        self.assertIsNone(new_assignment_grade)
                        mocked_update_assignment_grades_run.assert_not_called()
                        mocked_update_course_grades_run.assert_not_called()

                    # Resubmit of same comparison should fail
                    rv = self.client.post(self.base_url,
                                          data=json.dumps(comparison_submit),
                                          content_type='application/json')
                    self.assert400(rv)

                # all answers has been compared by the user, errors out when trying to get another pair
                rv = self.client.get(self.base_url)
                self.assert400(rv)