Пример #1
0
    def add_seq_with_content_groups(self, groups=None):
        """
        Adds sequential and two content groups to first course in courses list.
        """
        config_course_cohorts(self.courses[0], is_cohorted=True)

        if groups is None:
            groups = self.groups

        self.user_partition = UserPartition(id=0,
                                            name='Partition 1',
                                            description='This is partition 1',
                                            groups=groups,
                                            scheme=CohortPartitionScheme)

        self.user_partition.scheme.name = "cohort"

        ItemFactory.create(
            parent_location=self.chapter.location,
            category='sequential',
            display_name="Lesson 1",
            publish_item=True,
            metadata={u"user_partitions": [self.user_partition.to_json()]})

        self.first_cohort, self.second_cohort = [
            CohortFactory(course_id=self.courses[0].id) for _ in range(2)
        ]

        self.courses[0].user_partitions = [self.user_partition]
        self.courses[0].save()
        modulestore().update_item(self.courses[0], self.user.id)
    def add_seq_with_content_groups(self, groups=None):
        """
        Adds sequential and two content groups to first course in courses list.
        """
        config_course_cohorts(self.courses[0], is_cohorted=True)

        if groups is None:
            groups = self.groups

        self.user_partition = UserPartition(
            id=0,
            name='Partition 1',
            description='This is partition 1',
            groups=groups,
            scheme=CohortPartitionScheme
        )

        self.user_partition.scheme.name = "cohort"

        ItemFactory.create(
            parent_location=self.chapter.location,
            category='sequential',
            display_name="Lesson 1",
            publish_item=True,
            metadata={u"user_partitions": [self.user_partition.to_json()]}
        )

        self.first_cohort, self.second_cohort = [
            CohortFactory(course_id=self.courses[0].id) for _ in range(2)
        ]

        self.courses[0].user_partitions = [self.user_partition]
        self.courses[0].save()
        modulestore().update_item(self.courses[0], self.user.id)
Пример #3
0
    def test_add_to_valid_cohort(self):
        config_course_cohorts(self.course,
                              is_cohorted=True,
                              manual_cohorts=["cohort1", "cohort2"])
        response = self.request_bulk_enroll({
            'identifiers':
            self.notenrolled_student.username,
            'action':
            'enroll',
            'email_students':
            False,
            'courses':
            self.course_key,
            'cohorts':
            "cohort1"
        })

        self.assertEqual(response.status_code, 200)

        # test the response data
        expected = {
            "action": "enroll",
            'auto_enroll': False,
            "email_students": False,
            "courses": {
                self.course_key: {
                    "action":
                    "enroll",
                    'auto_enroll':
                    False,
                    "results": [{
                        "identifier": self.notenrolled_student.username,
                        "before": {
                            "enrollment": False,
                            "auto_enroll": False,
                            "user": True,
                            "allowed": False,
                            "cohort": None,
                        },
                        "after": {
                            "enrollment": True,
                            "auto_enroll": False,
                            "user": True,
                            "allowed": False,
                            "cohort": 'cohort1',
                        }
                    }]
                }
            }
        }
        manual_enrollments = ManualEnrollmentAudit.objects.all()
        self.assertEqual(manual_enrollments.count(), 1)
        self.assertEqual(manual_enrollments[0].state_transition,
                         UNENROLLED_TO_ENROLLED)
        res_json = json.loads(response.content.decode('utf-8'))
        self.assertIsNotNone(
            get_cohort_id(self.notenrolled_student,
                          CourseKey.from_string(self.course_key)))

        self.assertEqual(res_json, expected)
Пример #4
0
    def test_is_commentable_cohorted_team(self):
        course = modulestore().get_course(self.toy_course_key)
        self.assertFalse(cohorts.is_course_cohorted(course.id))

        config_course_cohorts(course, is_cohorted=True)
        team = CourseTeamFactory(course_id=course.id)

        # Verify that team discussions are not cohorted, but other discussions are
        self.assertFalse(utils.is_commentable_cohorted(course.id, team.discussion_topic_id))
        self.assertTrue(utils.is_commentable_cohorted(course.id, "random"))
    def test_post_cohortmembership_fix(self):
        """
        Test that changes made *after* migration, but *before* turning on new code are handled properly
        """
        # First, we're going to simulate some problem states that can arise during this window
        config_course_cohorts(self.course1, is_cohorted=True, auto_cohorts=["Course1AutoGroup1", "Course1AutoGroup2"])

        # Get the cohorts from the courses, which will cause auto cohorts to be created
        cohort_handler(self.request, unicode(self.course1.id))
        course_1_auto_cohort_1 = get_cohort_by_name(self.course1.id, "Course1AutoGroup1")
        course_1_auto_cohort_2 = get_cohort_by_name(self.course1.id, "Course1AutoGroup2")

        # When migrations were first run, the users were assigned to CohortMemberships correctly
        membership1 = CohortMembership(
            course_id=course_1_auto_cohort_1.course_id,
            user=self.user1,
            course_user_group=course_1_auto_cohort_1
        )
        membership1.save()
        membership2 = CohortMembership(
            course_id=course_1_auto_cohort_1.course_id,
            user=self.user2,
            course_user_group=course_1_auto_cohort_1
        )
        membership2.save()

        # But before CohortMembership code was turned on, some changes were made:
        course_1_auto_cohort_2.users.add(self.user1)  # user1 is now in 2 cohorts in the same course!
        course_1_auto_cohort_2.users.add(self.user2)
        course_1_auto_cohort_1.users.remove(self.user2)  # and user2 was moved, but no one told CohortMembership!

        # run the post-CohortMembership command, dry-run
        call_command('post_cohort_membership_fix')

        # Verify nothing was changed in dry-run mode.
        self.assertEqual(self.user1.course_groups.count(), 2)  # CourseUserGroup has 2 entries for user1

        self.assertEqual(CohortMembership.objects.get(user=self.user2).course_user_group.name, 'Course1AutoGroup1')
        user2_cohorts = list(self.user2.course_groups.values_list('name', flat=True))
        self.assertEqual(user2_cohorts, ['Course1AutoGroup2'])  # CourseUserGroup and CohortMembership disagree

        # run the post-CohortMembership command, and commit it
        call_command('post_cohort_membership_fix', commit='commit')

        # verify that both databases agree about the (corrected) state of the memberships
        self.assertEqual(self.user1.course_groups.count(), 1)
        self.assertEqual(CohortMembership.objects.filter(user=self.user1).count(), 1)

        self.assertEqual(self.user2.course_groups.count(), 1)
        self.assertEqual(CohortMembership.objects.filter(user=self.user2).count(), 1)
        self.assertEqual(CohortMembership.objects.get(user=self.user2).course_user_group.name, 'Course1AutoGroup2')
        user2_cohorts = list(self.user2.course_groups.values_list('name', flat=True))
        self.assertEqual(user2_cohorts, ['Course1AutoGroup2'])
    def test_post_cohortmembership_fix(self):
        """
        Test that changes made *after* migration, but *before* turning on new code are handled properly
        """
        # First, we're going to simulate some problem states that can arise during this window
        config_course_cohorts(self.course1, is_cohorted=True, auto_cohorts=["Course1AutoGroup1", "Course1AutoGroup2"])

        # Get the cohorts from the courses, which will cause auto cohorts to be created
        cohort_handler(self.request, unicode(self.course1.id))
        course_1_auto_cohort_1 = get_cohort_by_name(self.course1.id, "Course1AutoGroup1")
        course_1_auto_cohort_2 = get_cohort_by_name(self.course1.id, "Course1AutoGroup2")

        # When migrations were first run, the users were assigned to CohortMemberships correctly
        membership1 = CohortMembership(
            course_id=course_1_auto_cohort_1.course_id,
            user=self.user1,
            course_user_group=course_1_auto_cohort_1
        )
        membership1.save()
        membership2 = CohortMembership(
            course_id=course_1_auto_cohort_1.course_id,
            user=self.user2,
            course_user_group=course_1_auto_cohort_1
        )
        membership2.save()

        # But before CohortMembership code was turned on, some changes were made:
        course_1_auto_cohort_2.users.add(self.user1)  # user1 is now in 2 cohorts in the same course!
        course_1_auto_cohort_2.users.add(self.user2)
        course_1_auto_cohort_1.users.remove(self.user2)  # and user2 was moved, but no one told CohortMembership!

        # run the post-CohortMembership command, dry-run
        call_command('post_cohort_membership_fix')

        # Verify nothing was changed in dry-run mode.
        self.assertEqual(self.user1.course_groups.count(), 2)  # CourseUserGroup has 2 entries for user1

        self.assertEqual(CohortMembership.objects.get(user=self.user2).course_user_group.name, 'Course1AutoGroup1')
        user2_cohorts = list(self.user2.course_groups.values_list('name', flat=True))
        self.assertEqual(user2_cohorts, ['Course1AutoGroup2'])  # CourseUserGroup and CohortMembership disagree

        # run the post-CohortMembership command, and commit it
        call_command('post_cohort_membership_fix', commit='commit')

        # verify that both databases agree about the (corrected) state of the memberships
        self.assertEqual(self.user1.course_groups.count(), 1)
        self.assertEqual(CohortMembership.objects.filter(user=self.user1).count(), 1)

        self.assertEqual(self.user2.course_groups.count(), 1)
        self.assertEqual(CohortMembership.objects.filter(user=self.user2).count(), 1)
        self.assertEqual(CohortMembership.objects.get(user=self.user2).course_user_group.name, 'Course1AutoGroup2')
        user2_cohorts = list(self.user2.course_groups.values_list('name', flat=True))
        self.assertEqual(user2_cohorts, ['Course1AutoGroup2'])
Пример #7
0
 def test_allow_cohorts_when_enrolling(self):
     """
     Test if the cohorts are given but the action is unenroll.
     """
     config_course_cohorts(self.course, is_cohorted=True, manual_cohorts=["cohort1", "cohort2"])
     response = self.request_bulk_enroll({
         'identifiers': self.notenrolled_student.username,
         'action': 'unenroll',
         'email_students': False,
         'cohorts': 'cohort1',
         'courses': self.course_key
     })
     self.assertContains(response, 'Cohorts can only be used for enrollments.', status_code=400)
Пример #8
0
    def test_users_with_multiple_cohorts_cleanup(self):
        """
        Test that user which have been added in multiple cohorts of a course,
        can get cohorts without error after running cohorts cleanup command
        """
        # set two auto_cohort_groups for both courses
        config_course_cohorts(
            self.course1, [], cohorted=True, auto_cohort_groups=["Course1AutoGroup1", "Course1AutoGroup2"]
        )
        config_course_cohorts(
            self.course2, [], cohorted=True, auto_cohort_groups=["Course2AutoGroup1", "Course2AutoGroup2"]
        )

        # get the cohorts from the courses, which will cause auto cohorts to be created
        cohort_handler(self.request, unicode(self.course1.id))
        cohort_handler(self.request, unicode(self.course2.id))
        course_1_auto_cohort_1 = get_cohort_by_name(self.course1.id, "Course1AutoGroup1")
        course_1_auto_cohort_2 = get_cohort_by_name(self.course1.id, "Course1AutoGroup2")
        course_2_auto_cohort_1 = get_cohort_by_name(self.course2.id, "Course2AutoGroup1")

        # forcefully add user1 in two auto cohorts
        course_1_auto_cohort_1.users.add(self.user1)
        course_1_auto_cohort_2.users.add(self.user1)
        # forcefully add user2 in auto cohorts of both courses
        course_1_auto_cohort_1.users.add(self.user2)
        course_2_auto_cohort_1.users.add(self.user2)

        # now check that when user1 goes on discussion page and tries to get
        # cohorts 'MultipleObjectsReturned' exception is returned
        with self.assertRaises(MultipleObjectsReturned):
            get_cohort(self.user1, self.course1.id)
        # also check that user 2 can go on discussion page of both courses
        # without any exception
        get_cohort(self.user2, self.course1.id)
        get_cohort(self.user2, self.course2.id)

        # call command to remove users added in multiple cohorts of a course
        # are removed from all cohort groups
        call_command('remove_users_from_multiple_cohorts')

        # check that only user1 (with multiple cohorts) is removed from cohorts
        # and user2 is still in auto cohorts of both course after running
        # 'remove_users_from_multiple_cohorts' management command
        self.assertEqual(self.user1.course_groups.count(), 0)
        self.assertEqual(self.user2.course_groups.count(), 2)
        user2_cohorts = list(self.user2.course_groups.values_list('name', flat=True))
        self.assertEqual(user2_cohorts, ['Course1AutoGroup1', 'Course2AutoGroup1'])

        # now check that user1 can get cohorts in which he is added
        response = cohort_handler(self.request, unicode(self.course1.id))
        self.assertEqual(response.status_code, 200)
Пример #9
0
    def test_add_to_valid_cohort(self):
        config_course_cohorts(self.course, is_cohorted=True, manual_cohorts=["cohort1", "cohort2"])
        response = self.request_bulk_enroll({
            'identifiers': self.notenrolled_student.username,
            'action': 'enroll',
            'email_students': False,
            'courses': self.course_key,
            'cohorts': "cohort1"
        })

        self.assertEqual(response.status_code, 200)

        # test the response data
        expected = {
            "action": "enroll",
            'auto_enroll': False,
            "email_students": False,
            "courses": {
                self.course_key: {
                    "action": "enroll",
                    'auto_enroll': False,
                    "results": [
                        {
                            "identifier": self.notenrolled_student.username,
                            "before": {
                                "enrollment": False,
                                "auto_enroll": False,
                                "user": True,
                                "allowed": False,
                                "cohort": None,
                            },
                            "after": {
                                "enrollment": True,
                                "auto_enroll": False,
                                "user": True,
                                "allowed": False,
                                "cohort": 'cohort1',
                            }
                        }
                    ]
                }
            }
        }
        manual_enrollments = ManualEnrollmentAudit.objects.all()
        self.assertEqual(manual_enrollments.count(), 1)
        self.assertEqual(manual_enrollments[0].state_transition, UNENROLLED_TO_ENROLLED)
        res_json = json.loads(response.content)
        self.assertIsNotNone(get_cohort_id(self.notenrolled_student, CourseKey.from_string(self.course_key)))

        self.assertEqual(res_json, expected)
Пример #10
0
 def test_allow_cohorts_when_enrolling(self):
     """
     Test if the cohorts are given but the action is unenroll.
     """
     config_course_cohorts(self.course, is_cohorted=True, manual_cohorts=["cohort1", "cohort2"])
     response = self.request_bulk_enroll({
         'identifiers': self.notenrolled_student.username,
         'action': 'unenroll',
         'email_students': False,
         'cohorts': 'cohort1',
         'courses': self.course_key
     })
     self.assertEqual(response.status_code, 400)
     self.assertIn('Cohorts can only be used for enrollments.', response.content)
 def setup_chorts(self, course):
     """
     Sets up a cohort for each previously created user partition.
     """
     for user_partition in self.user_partitions:
         config_course_cohorts(course, is_cohorted=True)
         self.cohorts = []
         for group in self.groups:
             cohort = CohortFactory(course_id=course.id)
             self.cohorts.append(cohort)
             link_cohort_to_partition_group(
                 cohort,
                 user_partition.id,
                 group.id,
             )
 def setup_cohorts(self, course):
     """
     Sets up a cohort for each previously created user partition.
     """
     config_course_cohorts(course, is_cohorted=True)
     self.partition_cohorts = []
     for user_partition in self.user_partitions:
         partition_cohorts = []
         for group in self.groups:
             cohort = CohortFactory(course_id=course.id)
             partition_cohorts.append(cohort)
             link_cohort_to_partition_group(
                 cohort,
                 user_partition.id,
                 group.id,
             )
         self.partition_cohorts.append(partition_cohorts)
Пример #13
0
    def test_is_commentable_cohorted_inline_discussion(self):
        course = modulestore().get_course(self.toy_course_key)
        self.assertFalse(cohorts.is_course_cohorted(course.id))

        def to_id(name):  # pylint: disable=missing-docstring
            return topic_name_to_id(course, name)

        config_course_cohorts(
            course,
            is_cohorted=True,
            discussion_topics=["General", "Feedback"],
            cohorted_discussions=["Feedback", "random_inline"],
        )
        self.assertTrue(
            utils.is_commentable_cohorted(course.id, to_id("random")),
            "By default, Non-top-level discussion is always cohorted in cohorted courses.",
        )

        # if always_cohort_inline_discussions is set to False, non-top-level discussion are always
        # non cohorted unless they are explicitly set in cohorted_discussions
        config_course_cohorts(
            course,
            is_cohorted=True,
            discussion_topics=["General", "Feedback"],
            cohorted_discussions=["Feedback", "random_inline"],
            always_cohort_inline_discussions=False,
        )
        self.assertFalse(
            utils.is_commentable_cohorted(course.id, to_id("random")),
            "Non-top-level discussion is not cohorted if always_cohort_inline_discussions is False.",
        )
        self.assertTrue(
            utils.is_commentable_cohorted(course.id, to_id("random_inline")),
            "If always_cohort_inline_discussions set to False, Non-top-level discussion is "
            "cohorted if explicitly set in cohorted_discussions.",
        )
        self.assertTrue(
            utils.is_commentable_cohorted(course.id, to_id("Feedback")),
            "If always_cohort_inline_discussions set to False, top-level discussion are not affected.",
        )
Пример #14
0
    def test_is_commentable_cohorted(self):
        course = modulestore().get_course(self.toy_course_key)
        self.assertFalse(cohorts.is_course_cohorted(course.id))

        def to_id(name):
            """Helper for topic_name_to_id that uses course."""
            return topic_name_to_id(course, name)

        # no topics
        self.assertFalse(
            utils.is_commentable_cohorted(course.id, to_id("General")),
            "Course doesn't even have a 'General' topic"
        )

        # not cohorted
        config_course_cohorts(course, is_cohorted=False, discussion_topics=["General", "Feedback"])

        self.assertFalse(
            utils.is_commentable_cohorted(course.id, to_id("General")),
            "Course isn't cohorted"
        )

        # cohorted, but top level topics aren't
        config_course_cohorts(course, is_cohorted=True, discussion_topics=["General", "Feedback"])

        self.assertTrue(cohorts.is_course_cohorted(course.id))
        self.assertFalse(
            utils.is_commentable_cohorted(course.id, to_id("General")),
            "Course is cohorted, but 'General' isn't."
        )

        # cohorted, including "Feedback" top-level topics aren't
        config_course_cohorts(
            course,
            is_cohorted=True,
            discussion_topics=["General", "Feedback"],
            cohorted_discussions=["Feedback"]
        )

        self.assertTrue(cohorts.is_course_cohorted(course.id))
        self.assertFalse(
            utils.is_commentable_cohorted(course.id, to_id("General")),
            "Course is cohorted, but 'General' isn't."
        )
        self.assertTrue(
            utils.is_commentable_cohorted(course.id, to_id("Feedback")),
            "Feedback was listed as cohorted.  Should be."
        )
Пример #15
0
    def test_readd_to_different_cohort(self):
        config_course_cohorts(self.course, is_cohorted=True, manual_cohorts=["cohort1", "cohort2"])
        response = self.request_bulk_enroll({
            'identifiers': self.notenrolled_student.username,
            'action': 'enroll',
            'email_students': False,
            'courses': self.course_key,
            'cohorts': "cohort1"
        })

        assert response.status_code == 200

        # test the response data
        expected = {
            "action": "enroll",
            'auto_enroll': False,
            "email_students": False,
            "courses": {
                self.course_key: {
                    "action": "enroll",
                    'auto_enroll': False,
                    "results": [
                        {
                            "identifier": self.notenrolled_student.username,
                            "before": {
                                "enrollment": False,
                                "auto_enroll": False,
                                "user": True,
                                "allowed": False,
                                "cohort": None,
                            },
                            "after": {
                                "enrollment": True,
                                "auto_enroll": False,
                                "user": True,
                                "allowed": False,
                                "cohort": 'cohort1',
                            }
                        }
                    ]
                }
            }
        }
        manual_enrollments = ManualEnrollmentAudit.objects.all()
        assert manual_enrollments.count() == 1
        assert manual_enrollments[0].state_transition == UNENROLLED_TO_ENROLLED
        res_json = json.loads(response.content.decode('utf-8'))
        assert get_cohort_id(self.notenrolled_student, CourseKey.from_string(self.course_key)) is not None
        assert res_json == expected

        response2 = self.request_bulk_enroll({
            'identifiers': self.notenrolled_student.username,
            'action': 'enroll',
            'email_students': False,
            'courses': self.course_key,
            'cohorts': "cohort2"
        })

        assert response2.status_code == 200

        # test the response data
        expected2 = {
            "action": "enroll",
            'auto_enroll': False,
            "email_students": False,
            "courses": {
                self.course_key: {
                    "action": "enroll",
                    'auto_enroll': False,
                    "results": [
                        {
                            "identifier": self.notenrolled_student.username,
                            "before": {
                                "enrollment": True,
                                "auto_enroll": False,
                                "user": True,
                                "allowed": False,
                                "cohort": 'cohort1',
                            },
                            "after": {
                                "enrollment": True,
                                "auto_enroll": False,
                                "user": True,
                                "allowed": False,
                                "cohort": 'cohort2',
                            }
                        }
                    ]
                }
            }
        }
        res2_json = json.loads(response2.content.decode('utf-8'))
        assert get_cohort_id(self.notenrolled_student, CourseKey.from_string(self.course_key)) is not None
        assert res2_json == expected2