test_permissions.py 6.17 KB
Newer Older
1 2 3
"""
Test CRUD for authorization.
"""
4 5
import copy

6 7 8 9 10 11 12 13
from django.test.utils import override_settings
from django.contrib.auth.models import User, Group

from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from contentstore.tests.modulestore_config import TEST_MODULESTORE
from contentstore.tests.utils import AjaxEnabledTestClient
from xmodule.modulestore.django import loc_mapper
from xmodule.modulestore import Location
14 15 16
from student.roles import CourseInstructorRole, CourseStaffRole
from contentstore.views.access import has_course_access
from student import auth
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90


@override_settings(MODULESTORE=TEST_MODULESTORE)
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 = 'test+courses@edx.org'
        password = 'foo'

        # 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 = "user{}".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.
        """
91 92
        # first check the course creator.has explicit access (don't use has_access as is_staff
        # will trump the actual test)
93
        self.assertTrue(
94
            CourseInstructorRole(self.course_locator).has_user(self.user),
95 96 97
            "Didn't add creator as instructor."
        )
        users = copy.copy(self.users)
98
        # doesn't use role.users_with_role b/c it's verifying the roles.py behavior
99 100
        user_by_role = {}
        # add the misc users to the course in different groups
101
        for role in [CourseInstructorRole, CourseStaffRole]:
102
            user_by_role[role] = []
103 104 105 106 107 108
            # 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
109 110 111 112 113 114
            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()
115 116
                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))
117 118

        response = self.client.get_html(self.course_locator.url_reverse('course_team'))
119
        for role in [CourseInstructorRole, CourseStaffRole]:
120 121 122 123 124 125 126 127
            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
        )
128 129 130 131 132 133 134 135 136
        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]:
137
            for user in user_by_role[role]:
138 139 140 141 142 143 144 145 146 147
                # 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))