コード例 #1
0
class TestCourseListing(ModuleStoreTestCase):
    """
    Unit tests for getting the list of courses for a logged in user
    """
    def setUp(self):
        """
        Add a user and a course
        """
        super(TestCourseListing, self).setUp()
        # create and log in a staff user.
        # create and log in a non-staff user
        self.user = UserFactory()
        self.factory = RequestFactory()
        self.client = AjaxEnabledTestClient()
        self.client.login(username=self.user.username, password='******')

        source_course = CourseFactory.create(
            org='origin',
            number='the_beginning',
            run='first',
            display_name='the one and only',
            start=datetime.utcnow()
        )
        self.source_course_key = source_course.id

        for role in [CourseInstructorRole, CourseStaffRole]:
            role(self.source_course_key).add_users(self.user)

    def tearDown(self):
        """
        Reverse the setup
        """
        self.client.logout()
        ModuleStoreTestCase.tearDown(self)

    def test_rerun(self):
        """
        Just testing the functionality the view handler adds over the tasks tested in test_clone_course
        """
        response = self.client.ajax_post('/course/', {
            'source_course_key': unicode(self.source_course_key),
            'org': self.source_course_key.org, 'course': self.source_course_key.course, 'run': 'copy',
            'display_name': 'not the same old name',
        })
        self.assertEqual(response.status_code, 200)
        data = parse_json(response)
        dest_course_key = CourseKey.from_string(data['destination_course_key'])

        self.assertEqual(dest_course_key.run, 'copy')
        dest_course = self.store.get_course(dest_course_key)
        self.assertEqual(dest_course.start, CourseFields.start.default)
コード例 #2
0
class TestCourseAccess(ModuleStoreTestCase):
    """
    Course-based access (as opposed to access of a non-course xblock)
    """
    def setUp(self):
        """
        Create a staff user and log them in (creating the client).

        Create a pool of users w/o granting them any permissions
        """
        user_password = super(TestCourseAccess, self).setUp()

        self.client = AjaxEnabledTestClient()
        self.client.login(username=self.user.username, password=user_password)

        # create a course via the view handler which has a different strategy for permissions than the factory
        self.course_key = SlashSeparatedCourseKey('myu', 'mydept.mycourse', 'myrun')
        course_url = reverse_url('course_handler')
        self.client.ajax_post(
            course_url,
            {
                'org': self.course_key.org,
                'number': self.course_key.course,
                'display_name': 'My favorite course',
                'run': self.course_key.run,
            },
        )

        self.users = self._create_users()

    def _create_users(self):
        """
        Create 8 users and return them
        """
        users = []
        for i in range(8):
            username = "******".format(i)
            email = "test+user{}@edx.org".format(i)
            user = User.objects.create_user(username, email, 'foo')
            user.is_active = True
            user.save()
            users.append(user)
        return users

    def tearDown(self):
        """
        Reverse the setup
        """
        self.client.logout()
        ModuleStoreTestCase.tearDown(self)

    def test_get_all_users(self):
        """
        Test getting all authors for a course where their permissions run the gamut of allowed group
        types.
        """
        # first check the course creator.has explicit access (don't use has_access as is_staff
        # will trump the actual test)
        self.assertTrue(
            CourseInstructorRole(self.course_key).has_user(self.user),
            "Didn't add creator as instructor."
        )
        users = copy.copy(self.users)
        # doesn't use role.users_with_role b/c it's verifying the roles.py behavior
        user_by_role = {}
        # add the misc users to the course in different groups
        for role in [CourseInstructorRole, CourseStaffRole, OrgStaffRole, OrgInstructorRole]:
            user_by_role[role] = []
            # Org-based roles are created via org name, rather than course_key
            if (role is OrgStaffRole) or (role is OrgInstructorRole):
                group = role(self.course_key.org)
            else:
                group = role(self.course_key)
            # NOTE: this loop breaks the roles.py abstraction by purposely assigning
            # users to one of each possible groupname in order to test that has_course_author_access
            # and remove_user work
            user = users.pop()
            group.add_users(user)
            user_by_role[role].append(user)
            self.assertTrue(auth.has_course_author_access(user, self.course_key), "{} does not have access".format(user))

        course_team_url = reverse_course_url('course_team_handler', self.course_key)
        response = self.client.get_html(course_team_url)
        for role in [CourseInstructorRole, CourseStaffRole]:  # Global and org-based roles don't appear on this page
            for user in user_by_role[role]:
                self.assertContains(response, user.email)

        # test copying course permissions
        copy_course_key = SlashSeparatedCourseKey('copyu', 'copydept.mycourse', 'myrun')
        for role in [CourseInstructorRole, CourseStaffRole, OrgStaffRole, OrgInstructorRole]:
            if (role is OrgStaffRole) or (role is OrgInstructorRole):
                auth.add_users(
                    self.user,
                    role(copy_course_key.org),
                    *role(self.course_key.org).users_with_role()
                )
            else:
                auth.add_users(
                    self.user,
                    role(copy_course_key),
                    *role(self.course_key).users_with_role()
                )
        # verify access in copy course and verify that removal from source course w/ the various
        # groupnames works
        for role in [CourseInstructorRole, CourseStaffRole, OrgStaffRole, OrgInstructorRole]:
            for user in user_by_role[role]:
                # forcefully decache the groups: premise is that any real request will not have
                # multiple objects repr the same user but this test somehow uses different instance
                # in above add_users call
                if hasattr(user, '_roles'):
                    del user._roles

                self.assertTrue(auth.has_course_author_access(user, copy_course_key), "{} no copy access".format(user))
                if (role is OrgStaffRole) or (role is OrgInstructorRole):
                    auth.remove_users(self.user, role(self.course_key.org), user)
                else:
                    auth.remove_users(self.user, role(self.course_key), user)
                self.assertFalse(auth.has_course_author_access(user, self.course_key), "{} remove didn't work".format(user))
コード例 #3
0
class UnitTestLibraries(CourseTestCase):
    """
    Unit tests for library views
    """
    def setUp(self):
        super(UnitTestLibraries, self).setUp()

        self.client = AjaxEnabledTestClient()
        self.client.login(username=self.user.username,
                          password=self.user_password)

    ######################################################
    # Tests for /library/ - list and create libraries:

    @mock.patch("contentstore.views.library.LIBRARIES_ENABLED", False)
    def test_library_creator_status_libraries_not_enabled(self):
        _, nostaff_user = self.create_non_staff_authed_user_client()
        self.assertEqual(get_library_creator_status(nostaff_user), False)

    @mock.patch("contentstore.views.library.LIBRARIES_ENABLED", True)
    def test_library_creator_status_with_is_staff_user(self):
        self.assertEqual(get_library_creator_status(self.user), True)

    @mock.patch("contentstore.views.library.LIBRARIES_ENABLED", True)
    def test_library_creator_status_with_course_creator_role(self):
        _, nostaff_user = self.create_non_staff_authed_user_client()
        with mock.patch.dict('django.conf.settings.FEATURES',
                             {"ENABLE_CREATOR_GROUP": True}):
            grant_course_creator_status(self.user, nostaff_user)
            self.assertEqual(get_library_creator_status(nostaff_user), True)

    @mock.patch("contentstore.views.library.LIBRARIES_ENABLED", True)
    def test_library_creator_status_with_no_course_creator_role(self):
        _, nostaff_user = self.create_non_staff_authed_user_client()
        self.assertEqual(get_library_creator_status(nostaff_user), True)

    @ddt.data((False, False, True), (False, True, False), (True, False, True),
              (True, True, False), (True, None, False), (False, None, True))
    @ddt.unpack
    def test_library_creator_status_settings(self, disable_course,
                                             disable_library, expected_status):
        """
        Ensure that the setting DISABLE_LIBRARY_CREATION overrides DISABLE_COURSE_CREATION as expected.
        """
        _, nostaff_user = self.create_non_staff_authed_user_client()
        with mock.patch("contentstore.views.library.LIBRARIES_ENABLED", True):
            with mock.patch.dict(
                    "django.conf.settings.FEATURES", {
                        "DISABLE_COURSE_CREATION": disable_course,
                        "DISABLE_LIBRARY_CREATION": disable_library
                    }):
                self.assertEqual(get_library_creator_status(nostaff_user),
                                 expected_status)

    @mock.patch.dict('django.conf.settings.FEATURES',
                     {'DISABLE_COURSE_CREATION': True})
    @mock.patch("contentstore.views.library.LIBRARIES_ENABLED", True)
    def test_library_creator_status_with_no_course_creator_role_and_disabled_nonstaff_course_creation(
            self):
        """
        Ensure that `DISABLE_COURSE_CREATION` feature works with libraries as well.
        """
        nostaff_client, nostaff_user = self.create_non_staff_authed_user_client(
        )
        self.assertFalse(get_library_creator_status(nostaff_user))

        # To be explicit, this user can GET, but not POST
        get_response = nostaff_client.get_json(LIBRARY_REST_URL)
        post_response = nostaff_client.ajax_post(LIBRARY_REST_URL, {
            'org': 'org',
            'library': 'lib',
            'display_name': "New Library",
        })
        self.assertEqual(get_response.status_code, 200)
        self.assertEqual(post_response.status_code, 403)

    @patch("contentstore.views.library.LIBRARIES_ENABLED", False)
    def test_with_libraries_disabled(self):
        """
        The library URLs should return 404 if libraries are disabled.
        """
        response = self.client.get_json(LIBRARY_REST_URL)
        self.assertEqual(response.status_code, 404)

    def test_list_libraries(self):
        """
        Test that we can GET /library/ to list all libraries visible to the current user.
        """
        # Create some more libraries
        libraries = [LibraryFactory.create() for _ in range(3)]
        lib_dict = dict([(lib.location.library_key, lib) for lib in libraries])

        response = self.client.get_json(LIBRARY_REST_URL)
        self.assertEqual(response.status_code, 200)
        lib_list = parse_json(response)
        self.assertEqual(len(lib_list), len(libraries))
        for entry in lib_list:
            self.assertIn("library_key", entry)
            self.assertIn("display_name", entry)
            key = CourseKey.from_string(entry["library_key"])
            self.assertIn(key, lib_dict)
            self.assertEqual(entry["display_name"], lib_dict[key].display_name)
            del lib_dict[key]  # To ensure no duplicates are matched

    @ddt.data("delete", "put")
    def test_bad_http_verb(self, verb):
        """
        We should get an error if we do weird requests to /library/
        """
        response = getattr(self.client, verb)(LIBRARY_REST_URL)
        self.assertEqual(response.status_code, 405)

    def test_create_library(self):
        """ Create a library. """
        response = self.client.ajax_post(LIBRARY_REST_URL, {
            'org': 'org',
            'library': 'lib',
            'display_name': "New Library",
        })
        self.assertEqual(response.status_code, 200)
        # That's all we check. More detailed tests are in contentstore.tests.test_libraries...

    @patch.dict('django.conf.settings.FEATURES',
                {'ENABLE_CREATOR_GROUP': True})
    def test_lib_create_permission(self):
        """
        Users who are given course creator roles should be able to create libraries.
        """
        self.client.logout()
        ns_user, password = self.create_non_staff_user()
        self.client.login(username=ns_user.username, password=password)
        grant_course_creator_status(self.user, ns_user)
        response = self.client.ajax_post(LIBRARY_REST_URL, {
            'org': 'org',
            'library': 'lib',
            'display_name': "New Library",
        })
        self.assertEqual(response.status_code, 200)

    @patch.dict('django.conf.settings.FEATURES',
                {'ENABLE_CREATOR_GROUP': False})
    def test_lib_create_permission_no_course_creator_role_and_no_course_creator_group(
            self):
        """
        Users who are not given course creator roles should still be able to create libraries
        if ENABLE_CREATOR_GROUP is not enabled.
        """
        self.client.logout()
        ns_user, password = self.create_non_staff_user()
        self.client.login(username=ns_user.username, password=password)
        response = self.client.ajax_post(LIBRARY_REST_URL, {
            'org': 'org',
            'library': 'lib',
            'display_name': "New Library",
        })
        self.assertEqual(response.status_code, 200)

    @patch.dict('django.conf.settings.FEATURES',
                {'ENABLE_CREATOR_GROUP': True})
    def test_lib_create_permission_no_course_creator_role_and_course_creator_group(
            self):
        """
        Users who are not given course creator roles should not be able to create libraries
        if ENABLE_CREATOR_GROUP is enabled.
        """
        self.client.logout()
        ns_user, password = self.create_non_staff_user()
        self.client.login(username=ns_user.username, password=password)
        response = self.client.ajax_post(LIBRARY_REST_URL, {
            'org': 'org',
            'library': 'lib',
            'display_name': "New Library",
        })
        self.assertEqual(response.status_code, 403)

    @ddt.data(
        {},
        {'org': 'org'},
        {'library': 'lib'},
        {
            'org': 'C++',
            'library': 'lib',
            'display_name': 'Lib with invalid characters in key'
        },
        {
            'org': 'Org',
            'library': 'Wh@t?',
            'display_name': 'Lib with invalid characters in key'
        },
    )
    def test_create_library_invalid(self, data):
        """
        Make sure we are prevented from creating libraries with invalid keys/data
        """
        response = self.client.ajax_post(LIBRARY_REST_URL, data)
        self.assertEqual(response.status_code, 400)

    def test_no_duplicate_libraries(self):
        """
        We should not be able to create multiple libraries with the same key
        """
        lib = LibraryFactory.create()
        lib_key = lib.location.library_key
        response = self.client.ajax_post(
            LIBRARY_REST_URL, {
                'org': lib_key.org,
                'library': lib_key.library,
                'display_name': "A Duplicate key, same as 'lib'",
            })
        self.assertIn('already a library defined',
                      parse_json(response)['ErrMsg'])
        self.assertEqual(response.status_code, 400)

    ######################################################
    # Tests for /library/:lib_key/ - get a specific library as JSON or HTML editing view

    def test_get_lib_info(self):
        """
        Test that we can get data about a library (in JSON format) using /library/:key/
        """
        # Create a library
        lib_key = LibraryFactory.create().location.library_key
        # Re-load the library from the modulestore, explicitly including version information:
        lib = self.store.get_library(lib_key,
                                     remove_version=False,
                                     remove_branch=False)
        version = lib.location.library_key.version_guid
        self.assertNotEqual(version, None)

        response = self.client.get_json(make_url_for_lib(lib_key))
        self.assertEqual(response.status_code, 200)
        info = parse_json(response)
        self.assertEqual(info['display_name'], lib.display_name)
        self.assertEqual(info['library_id'], text_type(lib_key))
        self.assertEqual(info['previous_version'], None)
        self.assertNotEqual(info['version'], None)
        self.assertNotEqual(info['version'], '')
        self.assertEqual(info['version'], text_type(version))

    def test_get_lib_edit_html(self):
        """
        Test that we can get the studio view for editing a library using /library/:key/
        """
        lib = LibraryFactory.create()

        response = self.client.get(make_url_for_lib(lib.location.library_key))
        self.assertEqual(response.status_code, 200)
        self.assertIn("<html", response.content)
        self.assertIn(lib.display_name.encode('utf-8'), response.content)

    @ddt.data('library-v1:Nonexistent+library', 'course-v1:Org+Course',
              'course-v1:Org+Course+Run', 'invalid')
    def test_invalid_keys(self, key_str):
        """
        Check that various Nonexistent/invalid keys give 404 errors
        """
        response = self.client.get_json(make_url_for_lib(key_str))
        self.assertEqual(response.status_code, 404)

    def test_bad_http_verb_with_lib_key(self):
        """
        We should get an error if we do weird requests to /library/
        """
        lib = LibraryFactory.create()
        for verb in ("post", "delete", "put"):
            response = getattr(self.client, verb)(make_url_for_lib(
                lib.location.library_key))
            self.assertEqual(response.status_code, 405)

    def test_no_access(self):
        user, password = self.create_non_staff_user()
        self.client.login(username=user, password=password)

        lib = LibraryFactory.create()
        response = self.client.get(make_url_for_lib(lib.location.library_key))
        self.assertEqual(response.status_code, 403)

    def test_get_component_templates(self):
        """
        Verify that templates for adding discussion and advanced components to
        content libraries are not provided.
        """
        lib = LibraryFactory.create()
        lib.advanced_modules = ['lti']
        lib.save()
        templates = [
            template['type']
            for template in get_component_templates(lib, library=True)
        ]
        self.assertIn('problem', templates)
        self.assertNotIn('discussion', templates)
        self.assertNotIn('advanced', templates)

    def test_advanced_problem_types(self):
        """
        Verify that advanced problem types are not provided in problem component for libraries.
        """
        lib = LibraryFactory.create()
        lib.save()

        problem_type_templates = next(
            (component['templates']
             for component in get_component_templates(lib, library=True)
             if component['type'] == 'problem'), [])
        # Each problem template has a category which shows whether problem is a 'problem'
        # or which of the advanced problem type (e.g drag-and-drop-v2).
        problem_type_categories = [
            problem_template['category']
            for problem_template in problem_type_templates
        ]

        for advance_problem_type in settings.ADVANCED_PROBLEM_TYPES:
            self.assertNotIn(advance_problem_type['component'],
                             problem_type_categories)

    def test_manage_library_users(self):
        """
        Simple test that the Library "User Access" view works.
        Also tests that we can use the REST API to assign a user to a library.
        """
        library = LibraryFactory.create()
        extra_user, _ = self.create_non_staff_user()
        manage_users_url = reverse_library_url(
            'manage_library_users', text_type(library.location.library_key))

        response = self.client.get(manage_users_url)
        self.assertEqual(response.status_code, 200)
        # extra_user has not been assigned to the library so should not show up in the list:
        self.assertNotIn(binary_type(extra_user.username), response.content)

        # Now add extra_user to the library:
        user_details_url = reverse_course_url(
            'course_team_handler',
            library.location.library_key,
            kwargs={'email': extra_user.email})
        edit_response = self.client.ajax_post(user_details_url,
                                              {"role": LibraryUserRole.ROLE})
        self.assertIn(edit_response.status_code, (200, 204))

        # Now extra_user should apear in the list:
        response = self.client.get(manage_users_url)
        self.assertEqual(response.status_code, 200)
        self.assertIn(binary_type(extra_user.username), response.content)
コード例 #4
0
class TestUsersDefaultRole(ModuleStoreTestCase):
    """
    Unit tests for checking enrollment and default forum role "Student" of a logged in user
    """
    def setUp(self):
        """
        Add a user and a course
        """
        super(TestUsersDefaultRole, self).setUp()
        # create and log in a staff user.
        self.user = UserFactory(is_staff=True)  # pylint: disable=no-member
        self.client = AjaxEnabledTestClient()
        self.client.login(username=self.user.username, password='******')

        # create a course via the view handler to create course
        self.course_location = Location(['i4x', 'Org_1', 'Course_1', 'course', 'Run_1'])
        self._create_course_with_given_location(self.course_location)

    def _create_course_with_given_location(self, course_location):
        """
        Create course at provided location
        """
        course_locator = loc_mapper().translate_location(
            course_location.course_id, course_location, False, True
        )
        resp = self.client.ajax_post(
            course_locator.url_reverse('course'),
            {
                'org': course_location.org,
                'number': course_location.course,
                'display_name': 'test course',
                'run': course_location.name,
            }
        )
        return resp

    def tearDown(self):
        """
        Reverse the setup
        """
        self.client.logout()
        super(TestUsersDefaultRole, self).tearDown()

    def test_user_forum_default_role_on_course_deletion(self):
        """
        Test that a user enrolls and gets "Student" forum role for that course which he creates and remains
        enrolled even the course is deleted and keeps its "Student" forum role for that course
        """
        course_id = self.course_location.course_id
        # check that user has enrollment for this course
        self.assertTrue(CourseEnrollment.is_enrolled(self.user, course_id))

        # check that user has his default "Student" forum role for this course
        self.assertTrue(self.user.roles.filter(name="Student", course_id=course_id))  # pylint: disable=no-member

        delete_course_and_groups(course_id, commit=True)

        # check that user's enrollment for this course is not deleted
        self.assertTrue(CourseEnrollment.is_enrolled(self.user, course_id))

        # check that user has forum role for this course even after deleting it
        self.assertTrue(self.user.roles.filter(name="Student", course_id=course_id))  # pylint: disable=no-member

    def test_user_role_on_course_recreate(self):
        """
        Test that creating same course again after deleting it gives user his default
        forum role "Student" for that course
        """
        course_id = self.course_location.course_id
        # check that user has enrollment and his default "Student" forum role for this course
        self.assertTrue(CourseEnrollment.is_enrolled(self.user, course_id))
        self.assertTrue(self.user.roles.filter(name="Student", course_id=course_id))  # pylint: disable=no-member

        # delete this course and recreate this course with same user
        delete_course_and_groups(course_id, commit=True)
        resp = self._create_course_with_given_location(self.course_location)
        self.assertEqual(resp.status_code, 200)

        # check that user has his enrollment for this course
        self.assertTrue(CourseEnrollment.is_enrolled(self.user, course_id))

        # check that user has his default "Student" forum role for this course
        self.assertTrue(self.user.roles.filter(name="Student", course_id=course_id))  # pylint: disable=no-member

    def test_user_role_on_course_recreate_with_change_name_case(self):
        """
        Test that creating same course again with different name case after deleting it gives user
        his default forum role "Student" for that course
        """
        course_location = self.course_location
        # check that user has enrollment and his default "Student" forum role for this course
        self.assertTrue(CourseEnrollment.is_enrolled(self.user, course_location.course_id))
        # delete this course and recreate this course with same user
        delete_course_and_groups(course_location.course_id, commit=True)

        # now create same course with different name case ('uppercase')
        new_course_location = Location(
            ['i4x', course_location.org, course_location.course.upper(), 'course', course_location.name]
        )
        resp = self._create_course_with_given_location(new_course_location)
        self.assertEqual(resp.status_code, 200)

        # check that user has his default "Student" forum role again for this course (with changed name case)
        self.assertTrue(
            self.user.roles.filter(name="Student", course_id=new_course_location.course_id)  # pylint: disable=no-member
        )
コード例 #5
0
ファイル: test_library.py プロジェクト: shevious/edx-platform
class UnitTestLibraries(CourseTestCase):
    """
    Unit tests for library views
    """

    def setUp(self):
        super(UnitTestLibraries, self).setUp()

        self.client = AjaxEnabledTestClient()
        self.client.login(username=self.user.username, password=self.user_password)

    ######################################################
    # Tests for /library/ - list and create libraries:

    @mock.patch("contentstore.views.library.LIBRARIES_ENABLED", False)
    def test_library_creator_status_libraries_not_enabled(self):
        _, nostaff_user = self.create_non_staff_authed_user_client()
        self.assertEqual(get_library_creator_status(nostaff_user), False)

    @mock.patch("contentstore.views.library.LIBRARIES_ENABLED", True)
    def test_library_creator_status_with_is_staff_user(self):
        self.assertEqual(get_library_creator_status(self.user), True)

    @mock.patch("contentstore.views.library.LIBRARIES_ENABLED", True)
    def test_library_creator_status_with_course_creator_role(self):
        _, nostaff_user = self.create_non_staff_authed_user_client()
        with mock.patch.dict('django.conf.settings.FEATURES', {"ENABLE_CREATOR_GROUP": True}):
            grant_course_creator_status(self.user, nostaff_user)
            self.assertEqual(get_library_creator_status(nostaff_user), True)

    @mock.patch("contentstore.views.library.LIBRARIES_ENABLED", True)
    def test_library_creator_status_with_no_course_creator_role(self):
        _, nostaff_user = self.create_non_staff_authed_user_client()
        self.assertEqual(get_library_creator_status(nostaff_user), True)

    @patch("contentstore.views.library.LIBRARIES_ENABLED", False)
    def test_with_libraries_disabled(self):
        """
        The library URLs should return 404 if libraries are disabled.
        """
        response = self.client.get_json(LIBRARY_REST_URL)
        self.assertEqual(response.status_code, 404)

    def test_list_libraries(self):
        """
        Test that we can GET /library/ to list all libraries visible to the current user.
        """
        # Create some more libraries
        libraries = [LibraryFactory.create() for _ in range(3)]
        lib_dict = dict([(lib.location.library_key, lib) for lib in libraries])

        response = self.client.get_json(LIBRARY_REST_URL)
        self.assertEqual(response.status_code, 200)
        lib_list = parse_json(response)
        self.assertEqual(len(lib_list), len(libraries))
        for entry in lib_list:
            self.assertIn("library_key", entry)
            self.assertIn("display_name", entry)
            key = CourseKey.from_string(entry["library_key"])
            self.assertIn(key, lib_dict)
            self.assertEqual(entry["display_name"], lib_dict[key].display_name)
            del lib_dict[key]  # To ensure no duplicates are matched

    @ddt.data("delete", "put")
    def test_bad_http_verb(self, verb):
        """
        We should get an error if we do weird requests to /library/
        """
        response = getattr(self.client, verb)(LIBRARY_REST_URL)
        self.assertEqual(response.status_code, 405)

    def test_create_library(self):
        """ Create a library. """
        response = self.client.ajax_post(LIBRARY_REST_URL, {
            'org': 'org',
            'library': 'lib',
            'display_name': "New Library",
        })
        self.assertEqual(response.status_code, 200)
        # That's all we check. More detailed tests are in contentstore.tests.test_libraries...

    @patch.dict('django.conf.settings.FEATURES', {'ENABLE_CREATOR_GROUP': True})
    def test_lib_create_permission(self):
        """
        Users who are given course creator roles should be able to create libraries.
        """
        self.client.logout()
        ns_user, password = self.create_non_staff_user()
        self.client.login(username=ns_user.username, password=password)
        grant_course_creator_status(self.user, ns_user)
        response = self.client.ajax_post(LIBRARY_REST_URL, {
            'org': 'org', 'library': 'lib', 'display_name': "New Library",
        })
        self.assertEqual(response.status_code, 200)

    @patch.dict('django.conf.settings.FEATURES', {'ENABLE_CREATOR_GROUP': False})
    def test_lib_create_permission_no_course_creator_role_and_no_course_creator_group(self):
        """
        Users who are not given course creator roles should still be able to create libraries
        if ENABLE_CREATOR_GROUP is not enabled.
        """
        self.client.logout()
        ns_user, password = self.create_non_staff_user()
        self.client.login(username=ns_user.username, password=password)
        response = self.client.ajax_post(LIBRARY_REST_URL, {
            'org': 'org', 'library': 'lib', 'display_name': "New Library",
        })
        self.assertEqual(response.status_code, 200)

    @patch.dict('django.conf.settings.FEATURES', {'ENABLE_CREATOR_GROUP': True})
    def test_lib_create_permission_no_course_creator_role_and_course_creator_group(self):
        """
        Users who are not given course creator roles should not be able to create libraries
        if ENABLE_CREATOR_GROUP is enabled.
        """
        self.client.logout()
        ns_user, password = self.create_non_staff_user()
        self.client.login(username=ns_user.username, password=password)
        response = self.client.ajax_post(LIBRARY_REST_URL, {
            'org': 'org', 'library': 'lib', 'display_name': "New Library",
        })
        self.assertEqual(response.status_code, 403)

    @ddt.data(
        {},
        {'org': 'org'},
        {'library': 'lib'},
        {'org': 'C++', 'library': 'lib', 'display_name': 'Lib with invalid characters in key'},
        {'org': 'Org', 'library': 'Wh@t?', 'display_name': 'Lib with invalid characters in key'},
    )
    def test_create_library_invalid(self, data):
        """
        Make sure we are prevented from creating libraries with invalid keys/data
        """
        response = self.client.ajax_post(LIBRARY_REST_URL, data)
        self.assertEqual(response.status_code, 400)

    def test_no_duplicate_libraries(self):
        """
        We should not be able to create multiple libraries with the same key
        """
        lib = LibraryFactory.create()
        lib_key = lib.location.library_key
        response = self.client.ajax_post(LIBRARY_REST_URL, {
            'org': lib_key.org,
            'library': lib_key.library,
            'display_name': "A Duplicate key, same as 'lib'",
        })
        self.assertIn('already a library defined', parse_json(response)['ErrMsg'])
        self.assertEqual(response.status_code, 400)

    ######################################################
    # Tests for /library/:lib_key/ - get a specific library as JSON or HTML editing view

    def test_get_lib_info(self):
        """
        Test that we can get data about a library (in JSON format) using /library/:key/
        """
        # Create a library
        lib_key = LibraryFactory.create().location.library_key
        # Re-load the library from the modulestore, explicitly including version information:
        lib = self.store.get_library(lib_key, remove_version=False, remove_branch=False)
        version = lib.location.library_key.version_guid
        self.assertNotEqual(version, None)

        response = self.client.get_json(make_url_for_lib(lib_key))
        self.assertEqual(response.status_code, 200)
        info = parse_json(response)
        self.assertEqual(info['display_name'], lib.display_name)
        self.assertEqual(info['library_id'], unicode(lib_key))
        self.assertEqual(info['previous_version'], None)
        self.assertNotEqual(info['version'], None)
        self.assertNotEqual(info['version'], '')
        self.assertEqual(info['version'], unicode(version))

    def test_get_lib_edit_html(self):
        """
        Test that we can get the studio view for editing a library using /library/:key/
        """
        lib = LibraryFactory.create()

        response = self.client.get(make_url_for_lib(lib.location.library_key))
        self.assertEqual(response.status_code, 200)
        self.assertIn("<html", response.content)
        self.assertIn(lib.display_name, response.content)

    @ddt.data('library-v1:Nonexistent+library', 'course-v1:Org+Course', 'course-v1:Org+Course+Run', 'invalid')
    def test_invalid_keys(self, key_str):
        """
        Check that various Nonexistent/invalid keys give 404 errors
        """
        response = self.client.get_json(make_url_for_lib(key_str))
        self.assertEqual(response.status_code, 404)

    def test_bad_http_verb_with_lib_key(self):
        """
        We should get an error if we do weird requests to /library/
        """
        lib = LibraryFactory.create()
        for verb in ("post", "delete", "put"):
            response = getattr(self.client, verb)(make_url_for_lib(lib.location.library_key))
            self.assertEqual(response.status_code, 405)

    def test_no_access(self):
        user, password = self.create_non_staff_user()
        self.client.login(username=user, password=password)

        lib = LibraryFactory.create()
        response = self.client.get(make_url_for_lib(lib.location.library_key))
        self.assertEqual(response.status_code, 403)

    def test_get_component_templates(self):
        """
        Verify that templates for adding discussion and advanced components to
        content libraries are not provided.
        """
        lib = LibraryFactory.create()
        lib.advanced_modules = ['lti']
        lib.save()
        templates = [template['type'] for template in get_component_templates(lib, library=True)]
        self.assertIn('problem', templates)
        self.assertNotIn('discussion', templates)
        self.assertNotIn('advanced', templates)

    def test_manage_library_users(self):
        """
        Simple test that the Library "User Access" view works.
        Also tests that we can use the REST API to assign a user to a library.
        """
        library = LibraryFactory.create()
        extra_user, _ = self.create_non_staff_user()
        manage_users_url = reverse_library_url('manage_library_users', unicode(library.location.library_key))

        response = self.client.get(manage_users_url)
        self.assertEqual(response.status_code, 200)
        # extra_user has not been assigned to the library so should not show up in the list:
        self.assertNotIn(extra_user.username, response.content)

        # Now add extra_user to the library:
        user_details_url = reverse_course_url(
            'course_team_handler',
            library.location.library_key, kwargs={'email': extra_user.email}
        )
        edit_response = self.client.ajax_post(user_details_url, {"role": LibraryUserRole.ROLE})
        self.assertIn(edit_response.status_code, (200, 204))

        # Now extra_user should apear in the list:
        response = self.client.get(manage_users_url)
        self.assertEqual(response.status_code, 200)
        self.assertIn(extra_user.username, response.content)
コード例 #6
0
class TestCourseListing(ModuleStoreTestCase):
    """
    Unit tests for getting the list of courses for a logged in user
    """
    def setUp(self):
        """
        Add a user and a course
        """
        super(TestCourseListing, self).setUp()
        # create and log in a staff user.
        # create and log in a non-staff user
        self.user = UserFactory()
        self.factory = RequestFactory()
        self.client = AjaxEnabledTestClient()
        self.client.login(username=self.user.username, password='******')
        self.course_create_rerun_url = reverse('course_handler')
        source_course = CourseFactory.create(
            org='origin',
            number='the_beginning',
            run='first',
            display_name='the one and only',
            start=datetime.utcnow()
        )
        self.source_course_key = source_course.id

        for role in [CourseInstructorRole, CourseStaffRole]:
            role(self.source_course_key).add_users(self.user)

    def tearDown(self):
        """
        Reverse the setup
        """
        self.client.logout()
        ModuleStoreTestCase.tearDown(self)

    def test_rerun(self):
        """
        Just testing the functionality the view handler adds over the tasks tested in test_clone_course
        """
        response = self.client.ajax_post(self.course_create_rerun_url, {
            'source_course_key': unicode(self.source_course_key),
            'org': self.source_course_key.org, 'course': self.source_course_key.course, 'run': 'copy',
            'display_name': 'not the same old name',
        })
        self.assertEqual(response.status_code, 200)
        data = parse_json(response)
        dest_course_key = CourseKey.from_string(data['destination_course_key'])

        self.assertEqual(dest_course_key.run, 'copy')
        dest_course = self.store.get_course(dest_course_key)
        self.assertEqual(dest_course.start, CourseFields.start.default)

    @ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
    def test_newly_created_course_has_web_certs_enabled(self, store):
        """
        Tests newly created course has web certs enabled by default.
        """
        with modulestore().default_store(store):
            response = self.client.ajax_post(self.course_create_rerun_url, {
                'org': 'orgX',
                'number': 'CS101',
                'display_name': 'Course with web certs enabled',
                'run': '2015_T2'
            })
            self.assertEqual(response.status_code, 200)
            data = parse_json(response)
            new_course_key = CourseKey.from_string(data['course_key'])
            course = self.store.get_course(new_course_key)
            self.assertTrue(course.cert_html_view_enabled)

    @patch.dict('django.conf.settings.FEATURES', {'ORGANIZATIONS_APP': False})
    @ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
    def test_course_creation_without_org_app_enabled(self, store):
        """
        Tests course creation workflow should not create course to org
        link if organizations_app is not enabled.
        """
        with modulestore().default_store(store):
            response = self.client.ajax_post(self.course_create_rerun_url, {
                'org': 'orgX',
                'number': 'CS101',
                'display_name': 'Course with web certs enabled',
                'run': '2015_T2'
            })
            self.assertEqual(response.status_code, 200)
            data = parse_json(response)
            new_course_key = CourseKey.from_string(data['course_key'])
            course_orgs = get_course_organizations(new_course_key)
            self.assertEqual(course_orgs, [])

    @patch.dict('django.conf.settings.FEATURES', {'ORGANIZATIONS_APP': True})
    @ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
    def test_course_creation_with_org_not_in_system(self, store):
        """
        Tests course creation workflow when course organization does not exist
        in system.
        """
        with modulestore().default_store(store):
            response = self.client.ajax_post(self.course_create_rerun_url, {
                'org': 'orgX',
                'number': 'CS101',
                'display_name': 'Course with web certs enabled',
                'run': '2015_T2'
            })
            self.assertEqual(response.status_code, 400)
            data = parse_json(response)
            self.assertIn(u'Organization you selected does not exist in the system', data['error'])

    @patch.dict('django.conf.settings.FEATURES', {'ORGANIZATIONS_APP': True})
    @ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
    def test_course_creation_with_org_in_system(self, store):
        """
        Tests course creation workflow when course organization exist in system.
        """
        add_organization({
            'name': 'Test Organization',
            'short_name': 'orgX',
            'description': 'Testing Organization Description',
        })
        with modulestore().default_store(store):
            response = self.client.ajax_post(self.course_create_rerun_url, {
                'org': 'orgX',
                'number': 'CS101',
                'display_name': 'Course with web certs enabled',
                'run': '2015_T2'
            })
            self.assertEqual(response.status_code, 200)
            data = parse_json(response)
            new_course_key = CourseKey.from_string(data['course_key'])
            course_orgs = get_course_organizations(new_course_key)
            self.assertEqual(len(course_orgs), 1)
            self.assertEqual(course_orgs[0]['short_name'], 'orgX')
コード例 #7
0
class LibraryTestCase(ModuleStoreTestCase):
    """
    Common functionality for content libraries tests
    """
    def setUp(self):
        user_password = super(LibraryTestCase, self).setUp()

        self.client = AjaxEnabledTestClient()
        self.client.login(username=self.user.username, password=user_password)

        self.lib_key = self._create_library()
        self.library = modulestore().get_library(self.lib_key)

        self.session_data = {}  # Used by _bind_module

    def _create_library(self,
                        org="org",
                        library="lib",
                        display_name="Test Library"):
        """
        Helper method used to create a library. Uses the REST API.
        """
        response = self.client.ajax_post(LIBRARY_REST_URL, {
            'org': org,
            'library': library,
            'display_name': display_name,
        })
        self.assertEqual(response.status_code, 200)
        lib_info = parse_json(response)
        lib_key = CourseKey.from_string(lib_info['library_key'])
        self.assertIsInstance(lib_key, LibraryLocator)
        return lib_key

    def _add_library_content_block(self,
                                   course,
                                   library_key,
                                   other_settings=None):
        """
        Helper method to add a LibraryContent block to a course.
        The block will be configured to select content from the library
        specified by library_key.
        other_settings can be a dict of Scope.settings fields to set on the block.
        """
        return ItemFactory.create(category='library_content',
                                  parent_location=course.location,
                                  user_id=self.user.id,
                                  publish_item=False,
                                  source_library_id=unicode(library_key),
                                  **(other_settings or {}))

    def _add_simple_content_block(self):
        """ Adds simple HTML block to library """
        return ItemFactory.create(category="html",
                                  parent_location=self.library.location,
                                  user_id=self.user.id,
                                  publish_item=False)

    def _refresh_children(self, lib_content_block, status_code_expected=200):
        """
        Helper method: Uses the REST API to call the 'refresh_children' handler
        of a LibraryContent block
        """
        if 'user' not in lib_content_block.runtime._services:  # pylint: disable=protected-access
            user_service = DjangoXBlockUserService(self.user)
            lib_content_block.runtime._services['user'] = user_service  # pylint: disable=protected-access

        handler_url = reverse_usage_url('component_handler',
                                        lib_content_block.location,
                                        kwargs={'handler': 'refresh_children'})
        response = self.client.ajax_post(handler_url)
        self.assertEqual(response.status_code, status_code_expected)
        return modulestore().get_item(lib_content_block.location)

    def _bind_module(self, descriptor, user=None):
        """
        Helper to use the CMS's module system so we can access student-specific fields.
        """
        if user is None:
            user = self.user
        if user not in self.session_data:
            self.session_data[user] = {}
        request = Mock(user=user, session=self.session_data[user])
        _load_preview_module(request, descriptor)

    def _update_item(self, usage_key, metadata):
        """
        Helper method: Uses the REST API to update the fields of an XBlock.
        This will result in the XBlock's editor_saved() method being called.
        """
        update_url = reverse_usage_url("xblock_handler", usage_key)
        return self.client.ajax_post(update_url, data={
            'metadata': metadata,
        })

    def _list_libraries(self):
        """
        Use the REST API to get a list of libraries visible to the current user.
        """
        response = self.client.get_json(LIBRARY_REST_URL)
        self.assertEqual(response.status_code, 200)
        return parse_json(response)
コード例 #8
0
class UnitTestLibraries(ModuleStoreTestCase):
    """
    Unit tests for library views
    """
    def setUp(self):
        user_password = super(UnitTestLibraries, self).setUp()

        self.client = AjaxEnabledTestClient()
        self.client.login(username=self.user.username, password=user_password)

    ######################################################
    # Tests for /library/ - list and create libraries:

    @patch("contentstore.views.library.LIBRARIES_ENABLED", False)
    def test_with_libraries_disabled(self):
        """
        The library URLs should return 404 if libraries are disabled.
        """
        response = self.client.get_json(LIBRARY_REST_URL)
        self.assertEqual(response.status_code, 404)

    def test_list_libraries(self):
        """
        Test that we can GET /library/ to list all libraries visible to the current user.
        """
        # Create some more libraries
        libraries = [LibraryFactory.create() for _ in range(3)]
        lib_dict = dict([(lib.location.library_key, lib) for lib in libraries])

        response = self.client.get_json(LIBRARY_REST_URL)
        self.assertEqual(response.status_code, 200)
        lib_list = parse_json(response)
        self.assertEqual(len(lib_list), len(libraries))
        for entry in lib_list:
            self.assertIn("library_key", entry)
            self.assertIn("display_name", entry)
            key = CourseKey.from_string(entry["library_key"])
            self.assertIn(key, lib_dict)
            self.assertEqual(entry["display_name"], lib_dict[key].display_name)
            del lib_dict[key]  # To ensure no duplicates are matched

    @ddt.data("delete", "put")
    def test_bad_http_verb(self, verb):
        """
        We should get an error if we do weird requests to /library/
        """
        response = getattr(self.client, verb)(LIBRARY_REST_URL)
        self.assertEqual(response.status_code, 405)

    def test_create_library(self):
        """ Create a library. """
        response = self.client.ajax_post(LIBRARY_REST_URL, {
            'org': 'org',
            'library': 'lib',
            'display_name': "New Library",
        })
        self.assertEqual(response.status_code, 200)
        # That's all we check. More detailed tests are in contentstore.tests.test_libraries...

    @patch.dict('django.conf.settings.FEATURES',
                {'ENABLE_CREATOR_GROUP': True})
    def test_lib_create_permission(self):
        """
        Users who are not given course creator roles should still be able to
        create libraries.
        """
        self.client.logout()
        ns_user, password = self.create_non_staff_user()
        self.client.login(username=ns_user.username, password=password)

        response = self.client.ajax_post(LIBRARY_REST_URL, {
            'org': 'org',
            'library': 'lib',
            'display_name': "New Library",
        })
        self.assertEqual(response.status_code, 200)

    @ddt.data(
        {},
        {'org': 'org'},
        {'library': 'lib'},
        {
            'org': 'C++',
            'library': 'lib',
            'display_name': 'Lib with invalid characters in key'
        },
        {
            'org': 'Org',
            'library': 'Wh@t?',
            'display_name': 'Lib with invalid characters in key'
        },
    )
    def test_create_library_invalid(self, data):
        """
        Make sure we are prevented from creating libraries with invalid keys/data
        """
        response = self.client.ajax_post(LIBRARY_REST_URL, data)
        self.assertEqual(response.status_code, 400)

    def test_no_duplicate_libraries(self):
        """
        We should not be able to create multiple libraries with the same key
        """
        lib = LibraryFactory.create()
        lib_key = lib.location.library_key
        response = self.client.ajax_post(
            LIBRARY_REST_URL, {
                'org': lib_key.org,
                'library': lib_key.library,
                'display_name': "A Duplicate key, same as 'lib'",
            })
        self.assertIn('already a library defined',
                      parse_json(response)['ErrMsg'])
        self.assertEqual(response.status_code, 400)

    ######################################################
    # Tests for /library/:lib_key/ - get a specific library as JSON or HTML editing view

    def test_get_lib_info(self):
        """
        Test that we can get data about a library (in JSON format) using /library/:key/
        """
        # Create a library
        lib_key = LibraryFactory.create().location.library_key
        # Re-load the library from the modulestore, explicitly including version information:
        lib = self.store.get_library(lib_key,
                                     remove_version=False,
                                     remove_branch=False)
        version = lib.location.library_key.version_guid
        self.assertNotEqual(version, None)

        response = self.client.get_json(make_url_for_lib(lib_key))
        self.assertEqual(response.status_code, 200)
        info = parse_json(response)
        self.assertEqual(info['display_name'], lib.display_name)
        self.assertEqual(info['library_id'], unicode(lib_key))
        self.assertEqual(info['previous_version'], None)
        self.assertNotEqual(info['version'], None)
        self.assertNotEqual(info['version'], '')
        self.assertEqual(info['version'], unicode(version))

    def test_get_lib_edit_html(self):
        """
        Test that we can get the studio view for editing a library using /library/:key/
        """
        lib = LibraryFactory.create()

        response = self.client.get(make_url_for_lib(lib.location.library_key))
        self.assertEqual(response.status_code, 200)
        self.assertIn("<html", response.content)
        self.assertIn(lib.display_name, response.content)

    @ddt.data('library-v1:Nonexistent+library', 'course-v1:Org+Course',
              'course-v1:Org+Course+Run', 'invalid')
    def test_invalid_keys(self, key_str):
        """
        Check that various Nonexistent/invalid keys give 404 errors
        """
        response = self.client.get_json(make_url_for_lib(key_str))
        self.assertEqual(response.status_code, 404)

    def test_bad_http_verb_with_lib_key(self):
        """
        We should get an error if we do weird requests to /library/
        """
        lib = LibraryFactory.create()
        for verb in ("post", "delete", "put"):
            response = getattr(self.client, verb)(make_url_for_lib(
                lib.location.library_key))
            self.assertEqual(response.status_code, 405)

    def test_no_access(self):
        user, password = self.create_non_staff_user()
        self.client.login(username=user, password=password)

        lib = LibraryFactory.create()
        response = self.client.get(make_url_for_lib(lib.location.library_key))
        self.assertEqual(response.status_code, 403)

    def test_get_component_templates(self):
        """
        Verify that templates for adding discussion and advanced components to
        content libraries are not provided.
        """
        lib = LibraryFactory.create()
        lib.advanced_modules = ['lti']
        lib.save()
        templates = [
            template['type']
            for template in get_component_templates(lib, library=True)
        ]
        self.assertIn('problem', templates)
        self.assertNotIn('discussion', templates)
        self.assertNotIn('advanced', templates)

    def test_manage_library_users(self):
        """
        Simple test that the Library "User Access" view works.
        Also tests that we can use the REST API to assign a user to a library.
        """
        library = LibraryFactory.create()
        extra_user, _ = self.create_non_staff_user()
        manage_users_url = reverse_library_url(
            'manage_library_users', unicode(library.location.library_key))

        response = self.client.get(manage_users_url)
        self.assertEqual(response.status_code, 200)
        # extra_user has not been assigned to the library so should not show up in the list:
        self.assertNotIn(extra_user.username, response.content)

        # Now add extra_user to the library:
        user_details_url = reverse_course_url(
            'course_team_handler',
            library.location.library_key,
            kwargs={'email': extra_user.email})
        edit_response = self.client.ajax_post(user_details_url,
                                              {"role": LibraryUserRole.ROLE})
        self.assertIn(edit_response.status_code, (200, 204))

        # Now extra_user should apear in the list:
        response = self.client.get(manage_users_url)
        self.assertEqual(response.status_code, 200)
        self.assertIn(extra_user.username, response.content)
コード例 #9
0
class TestCourseAccess(ModuleStoreTestCase):
    """
    Course-based access (as opposed to access of a non-course xblock)
    """
    def setUp(self):
        """
        Create a staff user and log them in (creating the client).

        Create a pool of users w/o granting them any permissions
        """
        super(TestCourseAccess, self).setUp()
        uname = 'testuser'
        email = '*****@*****.**'
        password = '******'

        # Create the use so we can log them in.
        self.user = User.objects.create_user(uname, email, password)

        # Note that we do not actually need to do anything
        # for registration if we directly mark them active.
        self.user.is_active = True
        # Staff has access to view all courses
        self.user.is_staff = True
        self.user.save()

        self.client = AjaxEnabledTestClient()
        self.client.login(username=uname, password=password)

        # create a course via the view handler which has a different strategy for permissions than the factory
        self.course_key = SlashSeparatedCourseKey('myu', 'mydept.mycourse',
                                                  'myrun')
        course_url = reverse_url('course_handler')
        self.client.ajax_post(
            course_url, {
                'org': self.course_key.org,
                'number': self.course_key.course,
                'display_name': 'My favorite course',
                'run': self.course_key.run,
            })

        self.users = self._create_users()

    def _create_users(self):
        """
        Create 8 users and return them
        """
        users = []
        for i in range(8):
            username = "******".format(i)
            email = "test+user{}@edx.org".format(i)
            user = User.objects.create_user(username, email, 'foo')
            user.is_active = True
            user.save()
            users.append(user)
        return users

    def tearDown(self):
        """
        Reverse the setup
        """
        self.client.logout()
        ModuleStoreTestCase.tearDown(self)

    def test_get_all_users(self):
        """
        Test getting all authors for a course where their permissions run the gamut of allowed group
        types.
        """
        # first check the course creator.has explicit access (don't use has_access as is_staff
        # will trump the actual test)
        self.assertTrue(
            CourseInstructorRole(self.course_key).has_user(self.user),
            "Didn't add creator as instructor.")
        users = copy.copy(self.users)
        # doesn't use role.users_with_role b/c it's verifying the roles.py behavior
        user_by_role = {}
        # add the misc users to the course in different groups
        for role in [
                CourseInstructorRole, CourseStaffRole, OrgStaffRole,
                OrgInstructorRole
        ]:
            user_by_role[role] = []
            # Org-based roles are created via org name, rather than course_key
            if (role is OrgStaffRole) or (role is OrgInstructorRole):
                group = role(self.course_key.org)
            else:
                group = role(self.course_key)
            # NOTE: this loop breaks the roles.py abstraction by purposely assigning
            # users to one of each possible groupname in order to test that has_course_access
            # and remove_user work
            user = users.pop()
            group.add_users(user)
            user_by_role[role].append(user)
            self.assertTrue(has_course_access(user, self.course_key),
                            "{} does not have access".format(user))

        course_team_url = reverse_course_url('course_team_handler',
                                             self.course_key)
        response = self.client.get_html(course_team_url)
        for role in [CourseInstructorRole, CourseStaffRole
                     ]:  # Global and org-based roles don't appear on this page
            for user in user_by_role[role]:
                self.assertContains(response, user.email)

        # test copying course permissions
        copy_course_key = SlashSeparatedCourseKey('copyu', 'copydept.mycourse',
                                                  'myrun')
        for role in [
                CourseInstructorRole, CourseStaffRole, OrgStaffRole,
                OrgInstructorRole
        ]:
            if (role is OrgStaffRole) or (role is OrgInstructorRole):
                auth.add_users(self.user, role(copy_course_key.org),
                               *role(self.course_key.org).users_with_role())
            else:
                auth.add_users(self.user, role(copy_course_key),
                               *role(self.course_key).users_with_role())
        # verify access in copy course and verify that removal from source course w/ the various
        # groupnames works
        for role in [
                CourseInstructorRole, CourseStaffRole, OrgStaffRole,
                OrgInstructorRole
        ]:
            for user in user_by_role[role]:
                # forcefully decache the groups: premise is that any real request will not have
                # multiple objects repr the same user but this test somehow uses different instance
                # in above add_users call
                if hasattr(user, '_roles'):
                    del user._roles

                self.assertTrue(has_course_access(user, copy_course_key),
                                "{} no copy access".format(user))
                if (role is OrgStaffRole) or (role is OrgInstructorRole):
                    auth.remove_users(self.user, role(self.course_key.org),
                                      user)
                else:
                    auth.remove_users(self.user, role(self.course_key), user)
                self.assertFalse(has_course_access(user, self.course_key),
                                 "{} remove didn't work".format(user))
コード例 #10
0
class TestCourseAccess(ModuleStoreTestCase):
    """
    Course-based access (as opposed to access of a non-course xblock)
    """
    def setUp(self):
        """
        Create a staff user and log them in (creating the client).

        Create a pool of users w/o granting them any permissions
        """
        super(TestCourseAccess, self).setUp()
        uname = 'testuser'
        email = '*****@*****.**'
        password = '******'

        # Create the use so we can log them in.
        self.user = User.objects.create_user(uname, email, password)

        # Note that we do not actually need to do anything
        # for registration if we directly mark them active.
        self.user.is_active = True
        # Staff has access to view all courses
        self.user.is_staff = True
        self.user.save()

        self.client = AjaxEnabledTestClient()
        self.client.login(username=uname, password=password)

        # create a course via the view handler which has a different strategy for permissions than the factory
        self.course_location = Location(['i4x', 'myu', 'mydept.mycourse', 'course', 'myrun'])
        self.course_locator = loc_mapper().translate_location(
            self.course_location.course_id, self.course_location, False, True
        )
        self.client.ajax_post(
            self.course_locator.url_reverse('course'),
            {
                'org': self.course_location.org, 
                'number': self.course_location.course,
                'display_name': 'My favorite course',
                'run': self.course_location.name,
            }
        )

        self.users = self._create_users()

    def _create_users(self):
        """
        Create 8 users and return them
        """
        users = []
        for i in range(8):
            username = "******".format(i)
            email = "test+user{}@edx.org".format(i)
            user = User.objects.create_user(username, email, 'foo')
            user.is_active = True
            user.save()
            users.append(user)
        return users

    def tearDown(self):
        """
        Reverse the setup
        """
        self.client.logout()
        ModuleStoreTestCase.tearDown(self)

    def test_get_all_users(self):
        """
        Test getting all authors for a course where their permissions run the gamut of allowed group
        types.
        """
        # first check the groupname for the course creator.
        self.assertTrue(
            self.user.groups.filter(
                name="{}_{}".format(INSTRUCTOR_ROLE_NAME, self.course_locator.package_id)
            ).exists(),
            "Didn't add creator as instructor."
        )
        users = copy.copy(self.users)
        user_by_role = {}
        # add the misc users to the course in different groups
        for role in [INSTRUCTOR_ROLE_NAME, STAFF_ROLE_NAME]:
            user_by_role[role] = []
            groupnames, _ = authz.get_all_course_role_groupnames(self.course_locator, role)
            for groupname in groupnames:
                group, _ = Group.objects.get_or_create(name=groupname)
                user = users.pop()
                user_by_role[role].append(user)
                user.groups.add(group)
                user.save()
                self.assertTrue(has_access(user, self.course_locator), "{} does not have access".format(user))
                self.assertTrue(has_access(user, self.course_location), "{} does not have access".format(user))

        response = self.client.get_html(self.course_locator.url_reverse('course_team'))
        for role in [INSTRUCTOR_ROLE_NAME, STAFF_ROLE_NAME]:
            for user in user_by_role[role]:
                self.assertContains(response, user.email)
        
        # test copying course permissions
        copy_course_location = Location(['i4x', 'copyu', 'copydept.mycourse', 'course', 'myrun'])
        copy_course_locator = loc_mapper().translate_location(
            copy_course_location.course_id, copy_course_location, False, True
        )
        # pylint: disable=protected-access
        authz._copy_course_group(self.course_locator, copy_course_locator)
        for role in [INSTRUCTOR_ROLE_NAME, STAFF_ROLE_NAME]:
            for user in user_by_role[role]:
                self.assertTrue(has_access(user, copy_course_locator), "{} no copy access".format(user))
                self.assertTrue(has_access(user, copy_course_location), "{} no copy access".format(user))
コード例 #11
0
ファイル: test_libraries.py プロジェクト: dmohrC/edx-platform
class LibraryTestCase(ModuleStoreTestCase):
    """
    Common functionality for content libraries tests
    """

    def setUp(self):
        user_password = super(LibraryTestCase, self).setUp()

        self.client = AjaxEnabledTestClient()
        self.client.login(username=self.user.username, password=user_password)

        self.lib_key = self._create_library()
        self.library = modulestore().get_library(self.lib_key)

        self.session_data = {}  # Used by _bind_module

    def _create_library(self, org="org", library="lib", display_name="Test Library"):
        """
        Helper method used to create a library. Uses the REST API.
        """
        response = self.client.ajax_post(
            LIBRARY_REST_URL, {"org": org, "library": library, "display_name": display_name}
        )
        self.assertEqual(response.status_code, 200)
        lib_info = parse_json(response)
        lib_key = CourseKey.from_string(lib_info["library_key"])
        self.assertIsInstance(lib_key, LibraryLocator)
        return lib_key

    def _add_library_content_block(self, course, library_key, other_settings=None):
        """
        Helper method to add a LibraryContent block to a course.
        The block will be configured to select content from the library
        specified by library_key.
        other_settings can be a dict of Scope.settings fields to set on the block.
        """
        return ItemFactory.create(
            category="library_content",
            parent_location=course.location,
            user_id=self.user.id,
            publish_item=False,
            source_library_id=unicode(library_key),
            **(other_settings or {})
        )

    def _add_simple_content_block(self):
        """ Adds simple HTML block to library """
        return ItemFactory.create(
            category="html", parent_location=self.library.location, user_id=self.user.id, publish_item=False
        )

    def _refresh_children(self, lib_content_block, status_code_expected=200):
        """
        Helper method: Uses the REST API to call the 'refresh_children' handler
        of a LibraryContent block
        """
        if "user" not in lib_content_block.runtime._services:  # pylint: disable=protected-access
            mocked_user_service = Mock(user_id=self.user.id)
            mocked_user_service.get_current_user.return_value = XBlockUser(is_current_user=True)
            lib_content_block.runtime._services["user"] = mocked_user_service  # pylint: disable=protected-access

        handler_url = reverse_usage_url(
            "component_handler", lib_content_block.location, kwargs={"handler": "refresh_children"}
        )
        response = self.client.ajax_post(handler_url)
        self.assertEqual(response.status_code, status_code_expected)
        return modulestore().get_item(lib_content_block.location)

    def _bind_module(self, descriptor, user=None):
        """
        Helper to use the CMS's module system so we can access student-specific fields.
        """
        if user is None:
            user = self.user
        if user not in self.session_data:
            self.session_data[user] = {}
        request = Mock(user=user, session=self.session_data[user])
        _load_preview_module(request, descriptor)  # pylint: disable=protected-access

    def _update_item(self, usage_key, metadata):
        """
        Helper method: Uses the REST API to update the fields of an XBlock.
        This will result in the XBlock's editor_saved() method being called.
        """
        update_url = reverse_usage_url("xblock_handler", usage_key)
        return self.client.ajax_post(update_url, data={"metadata": metadata})

    def _list_libraries(self):
        """
        Use the REST API to get a list of libraries visible to the current user.
        """
        response = self.client.get_json(LIBRARY_REST_URL)
        self.assertEqual(response.status_code, 200)
        return parse_json(response)
コード例 #12
0
class TestCourseListing(ModuleStoreTestCase):
    """
    Unit tests for getting the list of courses for a logged in user
    """
    def setUp(self):
        """
        Add a user and a course
        """
        super(TestCourseListing, self).setUp()
        # create and log in a staff user.
        # create and log in a non-staff user
        self.user = UserFactory()
        self.factory = RequestFactory()
        self.client = AjaxEnabledTestClient()
        self.client.login(username=self.user.username, password='******')
        self.course_create_rerun_url = reverse('course_handler')
        source_course = CourseFactory.create(org='origin',
                                             number='the_beginning',
                                             run='first',
                                             display_name='the one and only',
                                             start=datetime.utcnow())
        self.source_course_key = source_course.id

        for role in [CourseInstructorRole, CourseStaffRole]:
            role(self.source_course_key).add_users(self.user)

    def tearDown(self):
        """
        Reverse the setup
        """
        self.client.logout()
        ModuleStoreTestCase.tearDown(self)

    def test_rerun(self):
        """
        Just testing the functionality the view handler adds over the tasks tested in test_clone_course
        """
        response = self.client.ajax_post(
            self.course_create_rerun_url, {
                'source_course_key': unicode(self.source_course_key),
                'org': self.source_course_key.org,
                'course': self.source_course_key.course,
                'run': 'copy',
                'display_name': 'not the same old name',
            })
        self.assertEqual(response.status_code, 200)
        data = parse_json(response)
        dest_course_key = CourseKey.from_string(data['destination_course_key'])

        self.assertEqual(dest_course_key.run, 'copy')
        dest_course = self.store.get_course(dest_course_key)
        self.assertEqual(dest_course.start, CourseFields.start.default)

    @ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
    def test_newly_created_course_has_web_certs_enabled(self, store):
        """
        Tests newly created course has web certs enabled by default.
        """
        with modulestore().default_store(store):
            response = self.client.ajax_post(
                self.course_create_rerun_url, {
                    'org': 'orgX',
                    'number': 'CS101',
                    'display_name': 'Course with web certs enabled',
                    'run': '2015_T2'
                })
            self.assertEqual(response.status_code, 200)
            data = parse_json(response)
            new_course_key = CourseKey.from_string(data['course_key'])
            course = self.store.get_course(new_course_key)
            self.assertTrue(course.cert_html_view_enabled)

    @patch.dict('django.conf.settings.FEATURES', {'ORGANIZATIONS_APP': False})
    @ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
    def test_course_creation_without_org_app_enabled(self, store):
        """
        Tests course creation workflow should not create course to org
        link if organizations_app is not enabled.
        """
        with modulestore().default_store(store):
            response = self.client.ajax_post(
                self.course_create_rerun_url, {
                    'org': 'orgX',
                    'number': 'CS101',
                    'display_name': 'Course with web certs enabled',
                    'run': '2015_T2'
                })
            self.assertEqual(response.status_code, 200)
            data = parse_json(response)
            new_course_key = CourseKey.from_string(data['course_key'])
            course_orgs = get_course_organizations(new_course_key)
            self.assertEqual(course_orgs, [])

    @patch.dict('django.conf.settings.FEATURES', {'ORGANIZATIONS_APP': True})
    @ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
    def test_course_creation_with_org_not_in_system(self, store):
        """
        Tests course creation workflow when course organization does not exist
        in system.
        """
        with modulestore().default_store(store):
            response = self.client.ajax_post(
                self.course_create_rerun_url, {
                    'org': 'orgX',
                    'number': 'CS101',
                    'display_name': 'Course with web certs enabled',
                    'run': '2015_T2'
                })
            self.assertEqual(response.status_code, 400)
            data = parse_json(response)
            self.assertIn(
                u'Organization you selected does not exist in the system',
                data['error'])

    @patch.dict('django.conf.settings.FEATURES', {'ORGANIZATIONS_APP': True})
    @ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
    def test_course_creation_with_org_in_system(self, store):
        """
        Tests course creation workflow when course organization exist in system.
        """
        add_organization({
            'name': 'Test Organization',
            'short_name': 'orgX',
            'description': 'Testing Organization Description',
        })
        with modulestore().default_store(store):
            response = self.client.ajax_post(
                self.course_create_rerun_url, {
                    'org': 'orgX',
                    'number': 'CS101',
                    'display_name': 'Course with web certs enabled',
                    'run': '2015_T2'
                })
            self.assertEqual(response.status_code, 200)
            data = parse_json(response)
            new_course_key = CourseKey.from_string(data['course_key'])
            course_orgs = get_course_organizations(new_course_key)
            self.assertEqual(len(course_orgs), 1)
            self.assertEqual(course_orgs[0]['short_name'], 'orgX')
コード例 #13
0
class TestUsersDefaultRole(ModuleStoreTestCase):
    """
    Unit tests for checking enrollment and default forum role "Student" of a logged in user
    """
    def setUp(self):
        """
        Add a user and a course
        """
        super(TestUsersDefaultRole, self).setUp()
        # create and log in a staff user.
        self.user = UserFactory(is_staff=True)  # pylint: disable=no-member
        self.client = AjaxEnabledTestClient()
        self.client.login(username=self.user.username, password='******')

        # create a course via the view handler to create course
        self.course_key = self.store.make_course_key('Org_1', 'Course_1', 'Run_1')
        self._create_course_with_given_location(self.course_key)

    def _create_course_with_given_location(self, course_key):
        """
        Create course at provided location
        """
        with mock.patch.dict('django.conf.settings.FEATURES', {"DEFAULT_STORE_FOR_NEW_COURSE": None}):
            resp = self.client.ajax_post(
                reverse_url('course_handler'),
                {
                    'org': course_key.org,
                    'number': course_key.course,
                    'display_name': 'test course',
                    'run': course_key.run,
                }
            )
        return resp

    def tearDown(self):
        """
        Reverse the setup
        """
        self.client.logout()
        super(TestUsersDefaultRole, self).tearDown()

    def test_user_forum_default_role_on_course_deletion(self):
        """
        Test that a user enrolls and gets "Student" forum role for that course which he creates and remains
        enrolled even the course is deleted and keeps its "Student" forum role for that course
        """
        # check that user has enrollment for this course
        self.assertTrue(CourseEnrollment.is_enrolled(self.user, self.course_key))

        # check that user has his default "Student" forum role for this course
        self.assertTrue(self.user.roles.filter(name="Student", course_id=self.course_key))  # pylint: disable=no-member

        delete_course_and_groups(self.course_key, self.user.id)

        # check that user's enrollment for this course is not deleted
        self.assertTrue(CourseEnrollment.is_enrolled(self.user, self.course_key))

        # check that user has forum role for this course even after deleting it
        self.assertTrue(self.user.roles.filter(name="Student", course_id=self.course_key))  # pylint: disable=no-member

    def test_user_role_on_course_recreate(self):
        """
        Test that creating same course again after deleting it gives user his default
        forum role "Student" for that course
        """
        # check that user has enrollment and his default "Student" forum role for this course
        self.assertTrue(CourseEnrollment.is_enrolled(self.user, self.course_key))
        self.assertTrue(self.user.roles.filter(name="Student", course_id=self.course_key))  # pylint: disable=no-member

        # delete this course and recreate this course with same user
        delete_course_and_groups(self.course_key, self.user.id)
        resp = self._create_course_with_given_location(self.course_key)
        self.assertEqual(resp.status_code, 200)

        # check that user has his enrollment for this course
        self.assertTrue(CourseEnrollment.is_enrolled(self.user, self.course_key))

        # check that user has his default "Student" forum role for this course
        self.assertTrue(self.user.roles.filter(name="Student", course_id=self.course_key))  # pylint: disable=no-member

    def test_user_role_on_course_recreate_with_change_name_case(self):
        """
        Test that creating same course again with different name case after deleting it gives user
        his default forum role "Student" for that course
        """
        # check that user has enrollment and his default "Student" forum role for this course
        self.assertTrue(CourseEnrollment.is_enrolled(self.user, self.course_key))
        # delete this course and recreate this course with same user
        delete_course_and_groups(self.course_key, self.user.id)

        # now create same course with different name case ('uppercase')
        new_course_key = self.course_key.replace(course=self.course_key.course.upper())
        resp = self._create_course_with_given_location(new_course_key)
        self.assertEqual(resp.status_code, 200)

        # check that user has his default "Student" forum role again for this course (with changed name case)
        self.assertTrue(
            self.user.roles.filter(name="Student", course_id=new_course_key)  # pylint: disable=no-member
        )
コード例 #14
0
class TestUsersDefaultRole(ModuleStoreTestCase):
    """
    Unit tests for checking enrollment and default forum role "Student" of a logged in user
    """

    def setUp(self):
        """
        Add a user and a course
        """
        super(TestUsersDefaultRole, self).setUp()
        # create and log in a staff user.
        self.user = UserFactory(is_staff=True)  # pylint: disable=no-member
        self.client = AjaxEnabledTestClient()
        self.client.login(username=self.user.username, password="******")

        # create a course via the view handler to create course
        self.course_key = SlashSeparatedCourseKey("Org_1", "Course_1", "Run_1")
        self._create_course_with_given_location(self.course_key)

    def _create_course_with_given_location(self, course_key):
        """
        Create course at provided location
        """
        resp = self.client.ajax_post(
            reverse_url("course_handler"),
            {"org": course_key.org, "number": course_key.course, "display_name": "test course", "run": course_key.run},
        )
        return resp

    def tearDown(self):
        """
        Reverse the setup
        """
        self.client.logout()
        super(TestUsersDefaultRole, self).tearDown()

    def test_user_forum_default_role_on_course_deletion(self):
        """
        Test that a user enrolls and gets "Student" forum role for that course which he creates and remains
        enrolled even the course is deleted and keeps its "Student" forum role for that course
        """
        # check that user has enrollment for this course
        self.assertTrue(CourseEnrollment.is_enrolled(self.user, self.course_key))

        # check that user has his default "Student" forum role for this course
        self.assertTrue(self.user.roles.filter(name="Student", course_id=self.course_key))  # pylint: disable=no-member

        delete_course_and_groups(self.course_key, self.user.id)

        # check that user's enrollment for this course is not deleted
        self.assertTrue(CourseEnrollment.is_enrolled(self.user, self.course_key))

        # check that user has forum role for this course even after deleting it
        self.assertTrue(self.user.roles.filter(name="Student", course_id=self.course_key))  # pylint: disable=no-member

    def test_user_role_on_course_recreate(self):
        """
        Test that creating same course again after deleting it gives user his default
        forum role "Student" for that course
        """
        # check that user has enrollment and his default "Student" forum role for this course
        self.assertTrue(CourseEnrollment.is_enrolled(self.user, self.course_key))
        self.assertTrue(self.user.roles.filter(name="Student", course_id=self.course_key))  # pylint: disable=no-member

        # delete this course and recreate this course with same user
        delete_course_and_groups(self.course_key, self.user.id)
        resp = self._create_course_with_given_location(self.course_key)
        self.assertEqual(resp.status_code, 200)

        # check that user has his enrollment for this course
        self.assertTrue(CourseEnrollment.is_enrolled(self.user, self.course_key))

        # check that user has his default "Student" forum role for this course
        self.assertTrue(self.user.roles.filter(name="Student", course_id=self.course_key))  # pylint: disable=no-member

    def test_user_role_on_course_recreate_with_change_name_case(self):
        """
        Test that creating same course again with different name case after deleting it gives user
        his default forum role "Student" for that course
        """
        # check that user has enrollment and his default "Student" forum role for this course
        self.assertTrue(CourseEnrollment.is_enrolled(self.user, self.course_key))
        # delete this course and recreate this course with same user
        delete_course_and_groups(self.course_key, self.user.id)

        # now create same course with different name case ('uppercase')
        new_course_key = self.course_key.replace(course=self.course_key.course.upper())
        resp = self._create_course_with_given_location(new_course_key)
        self.assertEqual(resp.status_code, 200)

        # check that user has his default "Student" forum role again for this course (with changed name case)
        self.assertTrue(self.user.roles.filter(name="Student", course_id=new_course_key))  # pylint: disable=no-member
コード例 #15
0
class TestCourseAccess(ModuleStoreTestCase):
    """
    Course-based access (as opposed to access of a non-course xblock)
    """
    def setUp(self):
        """
        Create a staff user and log them in (creating the client).

        Create a pool of users w/o granting them any permissions
        """
        super(TestCourseAccess, self).setUp()
        uname = 'testuser'
        email = '*****@*****.**'
        password = '******'

        # Create the use so we can log them in.
        self.user = User.objects.create_user(uname, email, password)

        # Note that we do not actually need to do anything
        # for registration if we directly mark them active.
        self.user.is_active = True
        # Staff has access to view all courses
        self.user.is_staff = True
        self.user.save()

        self.client = AjaxEnabledTestClient()
        self.client.login(username=uname, password=password)

        # create a course via the view handler which has a different strategy for permissions than the factory
        self.course_location = Location(['i4x', 'myu', 'mydept.mycourse', 'course', 'myrun'])
        self.course_locator = loc_mapper().translate_location(
            self.course_location.course_id, self.course_location, False, True
        )
        self.client.ajax_post(
            self.course_locator.url_reverse('course'),
            {
                'org': self.course_location.org, 
                'number': self.course_location.course,
                'display_name': 'My favorite course',
                'run': self.course_location.name,
            }
        )

        self.users = self._create_users()

    def _create_users(self):
        """
        Create 8 users and return them
        """
        users = []
        for i in range(8):
            username = "******".format(i)
            email = "test+user{}@edx.org".format(i)
            user = User.objects.create_user(username, email, 'foo')
            user.is_active = True
            user.save()
            users.append(user)
        return users

    def tearDown(self):
        """
        Reverse the setup
        """
        self.client.logout()
        ModuleStoreTestCase.tearDown(self)

    def test_get_all_users(self):
        """
        Test getting all authors for a course where their permissions run the gamut of allowed group
        types.
        """
        # first check the course creator.has explicit access (don't use has_access as is_staff
        # will trump the actual test)
        self.assertTrue(
            CourseInstructorRole(self.course_locator).has_user(self.user),
            "Didn't add creator as instructor."
        )
        users = copy.copy(self.users)
        # doesn't use role.users_with_role b/c it's verifying the roles.py behavior
        user_by_role = {}
        # add the misc users to the course in different groups
        for role in [CourseInstructorRole, CourseStaffRole]:
            user_by_role[role] = []
            # pylint: disable=protected-access
            groupnames = role(self.course_locator)._group_names
            self.assertGreater(len(groupnames), 1, "Only 0 or 1 groupname for {}".format(role.ROLE))
            # NOTE: this loop breaks the roles.py abstraction by purposely assigning
            # users to one of each possible groupname in order to test that has_course_access
            # and remove_user work
            for groupname in groupnames:
                group, _ = Group.objects.get_or_create(name=groupname)
                user = users.pop()
                user_by_role[role].append(user)
                user.groups.add(group)
                user.save()
                self.assertTrue(has_course_access(user, self.course_locator), "{} does not have access".format(user))
                self.assertTrue(has_course_access(user, self.course_location), "{} does not have access".format(user))

        response = self.client.get_html(self.course_locator.url_reverse('course_team'))
        for role in [CourseInstructorRole, CourseStaffRole]:
            for user in user_by_role[role]:
                self.assertContains(response, user.email)
        
        # test copying course permissions
        copy_course_location = Location(['i4x', 'copyu', 'copydept.mycourse', 'course', 'myrun'])
        copy_course_locator = loc_mapper().translate_location(
            copy_course_location.course_id, copy_course_location, False, True
        )
        for role in [CourseInstructorRole, CourseStaffRole]:
            auth.add_users(
                self.user,
                role(copy_course_locator),
                *role(self.course_locator).users_with_role()
            )
        # verify access in copy course and verify that removal from source course w/ the various
        # groupnames works
        for role in [CourseInstructorRole, CourseStaffRole]:
            for user in user_by_role[role]:
                # forcefully decache the groups: premise is that any real request will not have
                # multiple objects repr the same user but this test somehow uses different instance
                # in above add_users call
                if hasattr(user, '_groups'):
                    del user._groups

                self.assertTrue(has_course_access(user, copy_course_locator), "{} no copy access".format(user))
                self.assertTrue(has_course_access(user, copy_course_location), "{} no copy access".format(user))
                auth.remove_users(self.user, role(self.course_locator), user)
                self.assertFalse(has_course_access(user, self.course_locator), "{} remove didn't work".format(user))
コード例 #16
0
class TestCourseAccess(ModuleStoreTestCase):
    """
    Course-based access (as opposed to access of a non-course xblock)
    """
    def setUp(self):
        """
        Create a staff user and log them in (creating the client).

        Create a pool of users w/o granting them any permissions
        """
        super(TestCourseAccess, self).setUp()
        uname = 'testuser'
        email = '*****@*****.**'
        password = '******'

        # Create the use so we can log them in.
        self.user = User.objects.create_user(uname, email, password)

        # Note that we do not actually need to do anything
        # for registration if we directly mark them active.
        self.user.is_active = True
        # Staff has access to view all courses
        self.user.is_staff = True
        self.user.save()

        self.client = AjaxEnabledTestClient()
        self.client.login(username=uname, password=password)

        # create a course via the view handler which has a different strategy for permissions than the factory
        self.course_location = Location(['i4x', 'myu', 'mydept.mycourse', 'course', 'myrun'])
        self.course_locator = loc_mapper().translate_location(
            self.course_location.course_id, self.course_location, False, True
        )
        self.client.ajax_post(
            self.course_locator.url_reverse('course'),
            {
                'org': self.course_location.org, 
                'number': self.course_location.course,
                'display_name': 'My favorite course',
                'run': self.course_location.name,
            }
        )

        self.users = self._create_users()

    def _create_users(self):
        """
        Create 8 users and return them
        """
        users = []
        for i in range(8):
            username = "******".format(i)
            email = "test+user{}@edx.org".format(i)
            user = User.objects.create_user(username, email, 'foo')
            user.is_active = True
            user.save()
            users.append(user)
        return users

    def tearDown(self):
        """
        Reverse the setup
        """
        self.client.logout()
        ModuleStoreTestCase.tearDown(self)

    def test_get_all_users(self):
        """
        Test getting all authors for a course where their permissions run the gamut of allowed group
        types.
        """
        # first check the groupname for the course creator.
        self.assertTrue(
            self.user.groups.filter(
                name="{}_{}".format(INSTRUCTOR_ROLE_NAME, self.course_locator.course_id)
            ).exists(),
            "Didn't add creator as instructor."
        )
        users = copy.copy(self.users)
        user_by_role = {}
        # add the misc users to the course in different groups
        for role in [INSTRUCTOR_ROLE_NAME, STAFF_ROLE_NAME]:
            user_by_role[role] = []
            groupnames, _ = authz.get_all_course_role_groupnames(self.course_locator, role)
            for groupname in groupnames:
                group, _ = Group.objects.get_or_create(name=groupname)
                user = users.pop()
                user_by_role[role].append(user)
                user.groups.add(group)
                user.save()
                self.assertTrue(has_access(user, self.course_locator), "{} does not have access".format(user))
                self.assertTrue(has_access(user, self.course_location), "{} does not have access".format(user))

        response = self.client.get_html(self.course_locator.url_reverse('course_team'))
        for role in [INSTRUCTOR_ROLE_NAME, STAFF_ROLE_NAME]:
            for user in user_by_role[role]:
                self.assertContains(response, user.email)
        
        # test copying course permissions
        copy_course_location = Location(['i4x', 'copyu', 'copydept.mycourse', 'course', 'myrun'])
        copy_course_locator = loc_mapper().translate_location(
            copy_course_location.course_id, copy_course_location, False, True
        )
        # pylint: disable=protected-access
        authz._copy_course_group(self.course_locator, copy_course_locator)
        for role in [INSTRUCTOR_ROLE_NAME, STAFF_ROLE_NAME]:
            for user in user_by_role[role]:
                self.assertTrue(has_access(user, copy_course_locator), "{} no copy access".format(user))
                self.assertTrue(has_access(user, copy_course_location), "{} no copy access".format(user))