def test_update_creator_group(self): with mock.patch.dict('django.conf.settings.FEATURES', {"ENABLE_CREATOR_GROUP": True}): self.assertFalse(auth.user_has_role(self.user, CourseCreatorRole())) update_course_creator_group(self.admin, self.user, True) self.assertTrue(auth.user_has_role(self.user, CourseCreatorRole())) update_course_creator_group(self.admin, self.user, False) self.assertFalse(auth.user_has_role(self.user, CourseCreatorRole()))
def test_add_user_to_group_requires_staff_access(self): with self.assertRaises(PermissionDenied): self.admin.is_staff = False add_users(self.admin, CourseCreatorRole(), self.user) with self.assertRaises(PermissionDenied): add_users(self.user, CourseCreatorRole(), self.user)
def test_creator_group_enabled_but_empty(self): """ Tests creator group feature on, but group empty. """ with mock.patch.dict('django.conf.settings.FEATURES', {"ENABLE_CREATOR_GROUP": True}): self.assertFalse(user_has_role(self.user, CourseCreatorRole())) # Make user staff. This will cause CourseCreatorRole().has_user to return True. self.user.is_staff = True self.assertTrue(user_has_role(self.user, CourseCreatorRole()))
def test_add_user_not_active(self): """ Tests that adding to creator group fails if user is not active """ with mock.patch.dict('django.conf.settings.FEATURES', {'DISABLE_COURSE_CREATION': False, "ENABLE_CREATOR_GROUP": True}): self.user.is_active = False add_users(self.admin, CourseCreatorRole(), self.user) self.assertFalse(has_access(self.user, CourseCreatorRole()))
def update_course_creator_group(caller, user, add): """ Method for adding and removing users from the creator group. Caller must have staff permissions. """ if add: auth.add_users(caller, CourseCreatorRole(), user) else: auth.remove_users(caller, CourseCreatorRole(), user)
def test_creator_group_enabled_nonempty(self): """ Tests creator group feature on, user added. """ with mock.patch.dict('django.conf.settings.FEATURES', {"ENABLE_CREATOR_GROUP": True}): add_users(self.admin, CourseCreatorRole(), self.user) self.assertTrue(user_has_role(self.user, CourseCreatorRole())) # check that a user who has not been added to the group still returns false user_not_added = User.objects.create_user('testuser2', '*****@*****.**', 'foo2') self.assertFalse(user_has_role(user_not_added, CourseCreatorRole())) # remove first user from the group and verify that CourseCreatorRole().has_user now returns false remove_users(self.admin, CourseCreatorRole(), self.user) self.assertFalse(user_has_role(self.user, CourseCreatorRole()))
def test_add_granted(self): with mock.patch.dict('django.conf.settings.FEATURES', {"ENABLE_CREATOR_GROUP": True}): # Calling add_user_with_status_granted impacts is_user_in_course_group_role. self.assertFalse(auth.user_has_role(self.user, CourseCreatorRole())) add_user_with_status_granted(self.admin, self.user) self.assertEqual('granted', get_course_creator_status(self.user)) # Calling add again will be a no-op (even if state is different). add_user_with_status_unrequested(self.user) self.assertEqual('granted', get_course_creator_status(self.user)) self.assertTrue(auth.user_has_role(self.user, CourseCreatorRole()))
def _get_edly_user_info_cookie_string(request): """ Returns JWT encoded cookie string with edly user info. Arguments: request (HttpRequest): Django request object Returns: string """ try: edly_sub_organization = request.site.edly_sub_org_for_lms edly_user_info_cookie_data = { 'edly-org': edly_sub_organization.edly_organization.slug, 'edly-sub-org': edly_sub_organization.slug, 'edx-org': edly_sub_organization.edx_organization.short_name, 'is_course_creator': auth.user_has_role(request.user, CourseCreatorRole()) if getattr( request, 'user', None) else False, } return encode_edly_user_info_cookie(edly_user_info_cookie_data) except EdlySubOrganization.DoesNotExist: return ''
def test_set_global_course_creator_status(self): """ Test that "set_global_course_creator_status" method sets/removes a User as Global Course Creator correctly. """ self._create_edly_sub_organization() response = cookies_api.set_logged_in_edly_cookies( self.request, HttpResponse(), self.user, cookie_settings(self.request)) self._copy_cookies_to_request(response, self.request) edly_user_info_cookie = self.request.COOKIES.get( settings.EDLY_USER_INFO_COOKIE_NAME) edx_org = get_edx_org_from_cookie(edly_user_info_cookie) self.request.user = self.admin_user set_global_course_creator_status(self.request, self.user, True) assert self._get_course_creator_status(self.user) == 'granted' assert auth.user_has_role(self.user, GlobalCourseCreatorRole(edx_org)) set_global_course_creator_status(self.request, self.user, False) assert self._get_course_creator_status(self.user) == 'unrequested' assert not auth.user_has_role(self.user, GlobalCourseCreatorRole(edx_org)) self.admin_user.is_staff = False self.admin_user.save() with self.assertRaises(PermissionDenied): set_global_course_creator_status(self.request, self.user, True) edly_panel_admin_user_group, __ = Group.objects.get_or_create( name=settings.EDLY_PANEL_ADMIN_USERS_GROUP) self.admin_user.groups.add(edly_panel_admin_user_group) set_global_course_creator_status(self.request, self.user, True) assert self._get_course_creator_status(self.user) == 'granted' assert auth.user_has_role(self.user, CourseCreatorRole())
def test_course_creation_disabled(self): """ Tests that the COURSE_CREATION_DISABLED flag overrides course creator group settings. """ with mock.patch.dict('django.conf.settings.FEATURES', {'DISABLE_COURSE_CREATION': True, "ENABLE_CREATOR_GROUP": True}): # Add user to creator group. add_users(self.admin, CourseCreatorRole(), self.user) # DISABLE_COURSE_CREATION overrides (user is not marked as staff). self.assertFalse(user_has_role(self.user, CourseCreatorRole())) # Mark as staff. Now CourseCreatorRole().has_user returns true. self.user.is_staff = True self.assertTrue(user_has_role(self.user, CourseCreatorRole())) # Remove user from creator group. CourseCreatorRole().has_user still returns true because is_staff=True remove_users(self.admin, CourseCreatorRole(), self.user) self.assertTrue(user_has_role(self.user, CourseCreatorRole()))
def test_remove_user_from_group_requires_authenticated(self): with self.assertRaises(PermissionDenied): with mock.patch( 'django.contrib.auth.models.User.is_authenticated', new_callable=mock.PropertyMock ) as mock_is_auth: mock_is_auth.return_value = False remove_users(self.admin, CourseCreatorRole(), self.user)
def _create_library(request): """ Helper method for creating a new library. """ if not auth.has_access(request.user, CourseCreatorRole()): log.exception(u"User %s tried to create a library without permission", request.user.username) raise PermissionDenied() display_name = None try: display_name = request.json['display_name'] org = request.json['org'] library = request.json.get('number', None) if library is None: library = request.json['library'] store = modulestore() with store.default_store(ModuleStoreEnum.Type.split): new_lib = store.create_library( org=org, library=library, user_id=request.user.id, fields={"display_name": display_name}, ) # Give the user admin ("Instructor") role for this library: add_instructor(new_lib.location.library_key, request.user, request.user) except KeyError as error: log.exception("Unable to create library - missing required JSON key.") return JsonResponseBadRequest({ "ErrMsg": _("Unable to create library - missing required field '{field}'". format(field=error.message)) }) except InvalidKeyError as error: log.exception("Unable to create library - invalid key.") return JsonResponseBadRequest({ "ErrMsg": _("Unable to create library '{name}'.\n\n{err}").format( name=display_name, err=error.message) }) except DuplicateCourseError: log.exception( "Unable to create library - one already exists with the same key.") return JsonResponseBadRequest({ 'ErrMsg': _('There is already a library defined with the same ' 'organization and library code. Please ' 'change your library code so that it is unique within your organization.' ) }) lib_key_str = unicode(new_lib.location.library_key) return JsonResponse({ 'url': reverse_library_url('library_handler', lib_key_str), 'library_key': lib_key_str, })
def test_add_user_not_authenticated(self): """ Tests that adding to creator group fails if user is not authenticated """ with mock.patch.dict('django.conf.settings.FEATURES', { 'DISABLE_COURSE_CREATION': False, "ENABLE_CREATOR_GROUP": True }): anonymous_user = AnonymousUser() role = CourseCreatorRole() add_users(self.admin, role, anonymous_user) self.assertFalse(user_has_role(anonymous_user, role))
def test_update_course_creator_status(self): """ Test that "update_course_creator_status" method sets/removes a User as Course Creator correctly. """ settings.FEATURES['ENABLE_CREATOR_GROUP'] = True update_course_creator_status(self.admin_user, self.user, True) assert self._get_course_creator_status(self.user) == 'granted' assert auth.user_has_role(self.user, CourseCreatorRole()) update_course_creator_status(self.admin_user, self.user, False) assert self._get_course_creator_status(self.user) == 'unrequested' assert not auth.user_has_role(self.user, CourseCreatorRole()) self.admin_user.is_staff = False self.admin_user.save() with self.assertRaises(PermissionDenied): update_course_creator_status(self.admin_user, self.user, True) edly_panel_admin_user_group, __ = Group.objects.get_or_create( name=settings.EDLY_PANEL_ADMIN_USERS_GROUP) self.admin_user.groups.add(edly_panel_admin_user_group) update_course_creator_status(self.admin_user, self.user, False) assert self._get_course_creator_status(self.user) == 'unrequested' assert not auth.user_has_role(self.user, CourseCreatorRole())
def change_state_and_verify_email(state, is_creator): """ Changes user state, verifies creator status, and verifies e-mail is sent based on transition """ self._change_state(state) self.assertEqual(is_creator, auth.user_has_role(self.user, CourseCreatorRole())) context = {'studio_request_email': self.studio_request_email} if state == CourseCreator.GRANTED: template = 'emails/course_creator_granted.txt' elif state == CourseCreator.DENIED: template = 'emails/course_creator_denied.txt' else: template = 'emails/course_creator_revoked.txt' email_user.assert_called_with( mock_render_to_string('emails/course_creator_subject.txt', context), mock_render_to_string(template, context), self.studio_request_email )
def test_change_status(self, email_user): """ Tests that updates to state impact the creator group maintained in authz.py and that e-mails are sent. """ def change_state_and_verify_email(state, is_creator): """ Changes user state, verifies creator status, and verifies e-mail is sent based on transition """ self._change_state(state) self.assertEqual( is_creator, auth.user_has_role(self.user, CourseCreatorRole())) context = {'studio_request_email': self.studio_request_email} if state == CourseCreator.GRANTED: template = 'emails/course_creator_granted.txt' elif state == CourseCreator.DENIED: template = 'emails/course_creator_denied.txt' else: template = 'emails/course_creator_revoked.txt' email_user.assert_called_with( mock_render_to_string('emails/course_creator_subject.txt', context), mock_render_to_string(template, context), self.studio_request_email) with mock.patch.dict('django.conf.settings.FEATURES', self.enable_creator_group_patch): # User is initially unrequested. self.assertFalse(auth.user_has_role(self.user, CourseCreatorRole())) change_state_and_verify_email(CourseCreator.GRANTED, True) change_state_and_verify_email(CourseCreator.DENIED, False) change_state_and_verify_email(CourseCreator.GRANTED, True) change_state_and_verify_email(CourseCreator.PENDING, False) change_state_and_verify_email(CourseCreator.GRANTED, True) change_state_and_verify_email(CourseCreator.UNREQUESTED, False) change_state_and_verify_email(CourseCreator.DENIED, False)
def test_creation(self): """ The user that creates a library should have instructor (admin) and staff permissions """ # self.library has been auto-created by the staff user. self.assertTrue(has_studio_write_access(self.user, self.lib_key)) self.assertTrue(has_studio_read_access(self.user, self.lib_key)) # Make sure the user was actually assigned the instructor role and not just using is_staff superpowers: self.assertTrue(CourseInstructorRole(self.lib_key).has_user(self.user)) # Now log out and ensure we are forbidden from creating a library: self.client.logout() self._assert_cannot_create_library(expected_code=302) # 302 redirect to login expected # Now create a non-staff user with no permissions: self._login_as_non_staff_user(logout_first=False) self.assertFalse(CourseCreatorRole().has_user(self.non_staff_user)) # Now check that logged-in users without any permissions cannot create libraries with patch.dict('django.conf.settings.FEATURES', {'ENABLE_CREATOR_GROUP': True}): self._assert_cannot_create_library()
def test_get_edly_cookie_string(self): """ Tests that edly cookie string is generated correctly. """ edly_sub_organization = self._create_edly_sub_organization() actual_cookie_string = cookies_api._get_edly_user_info_cookie_string( self.request) # pylint: disable=protected-access expected_cookie_string = jwt.encode( { 'edly-org': edly_sub_organization.edly_organization.slug, 'edly-sub-org': edly_sub_organization.slug, 'edx-org': edly_sub_organization.edx_organization.short_name, 'is_course_creator': auth.user_has_role(self.request.user, CourseCreatorRole()), }, settings.EDLY_COOKIE_SECRET_KEY, algorithm=settings.EDLY_JWT_ALGORITHM) assert actual_cookie_string == expected_cookie_string
def create_new_course(request): """ Create a new course. Returns the URL for the course overview page. """ if not auth.has_access(request.user, CourseCreatorRole()): raise PermissionDenied() org = request.json.get('org') number = request.json.get('number') display_name = request.json.get('display_name') run = request.json.get('run') # allow/disable unicode characters in course_id according to settings if not settings.FEATURES.get('ALLOW_UNICODE_COURSE_ID'): if _has_non_ascii_characters(org) or _has_non_ascii_characters( number) or _has_non_ascii_characters(run): return JsonResponse( { 'error': _('Special characters not allowed in organization, course number, and course run.' ) }, status=400) try: dest_location = Location(u'i4x', org, number, u'course', run) except InvalidLocationError as error: return JsonResponse({ "ErrMsg": _("Unable to create course '{name}'.\n\n{err}").format( name=display_name, err=error.message) }) # see if the course already exists existing_course = None try: existing_course = modulestore('direct').get_item(dest_location) except ItemNotFoundError: pass if existing_course is not None: return JsonResponse({ 'ErrMsg': _('There is already a course defined with the same ' 'organization, course number, and course run. Please ' 'change either organization or course number to be ' 'unique.'), 'OrgErrMsg': _('Please change either the organization or ' 'course number so that it is unique.'), 'CourseErrMsg': _('Please change either the organization or ' 'course number so that it is unique.'), }) # dhm: this query breaks the abstraction, but I'll fix it when I do my suspended refactoring of this # file for new locators. get_items should accept a query rather than requiring it be a legal location course_search_location = bson.son.SON({ '_id.tag': 'i4x', # cannot pass regex to Location constructor; thus this hack # pylint: disable=E1101 '_id.org': re.compile(u'^{}$'.format(dest_location.org), re.IGNORECASE | re.UNICODE), # pylint: disable=E1101 '_id.course': re.compile(u'^{}$'.format(dest_location.course), re.IGNORECASE | re.UNICODE), '_id.category': 'course', }) courses = modulestore().collection.find(course_search_location, fields=('_id')) if courses.count() > 0: return JsonResponse({ 'ErrMsg': _('There is already a course defined with the same ' 'organization and course number. Please ' 'change at least one field to be unique.'), 'OrgErrMsg': _('Please change either the organization or ' 'course number so that it is unique.'), 'CourseErrMsg': _('Please change either the organization or ' 'course number so that it is unique.'), }) # instantiate the CourseDescriptor and then persist it # note: no system to pass if display_name is None: metadata = {} else: metadata = {'display_name': display_name} # Set a unique wiki_slug for newly created courses. To maintain active wiki_slugs for existing xml courses this # cannot be changed in CourseDescriptor. wiki_slug = "{0}.{1}.{2}".format(dest_location.org, dest_location.course, dest_location.name) definition_data = {'wiki_slug': wiki_slug} modulestore('direct').create_and_save_xmodule( dest_location, definition_data=definition_data, metadata=metadata) new_course = modulestore('direct').get_item(dest_location) # clone a default 'about' overview module as well dest_about_location = dest_location.replace(category='about', name='overview') overview_template = AboutDescriptor.get_template('overview.yaml') modulestore('direct').create_and_save_xmodule( dest_about_location, system=new_course.system, definition_data=overview_template.get('data')) initialize_course_tabs(new_course, request.user) new_location = loc_mapper().translate_location( new_course.location.course_id, new_course.location, False, True) # can't use auth.add_users here b/c it requires request.user to already have Instructor perms in this course # however, we can assume that b/c this user had authority to create the course, the user can add themselves CourseInstructorRole(new_location).add_users(request.user) auth.add_users(request.user, CourseStaffRole(new_location), request.user) # seed the forums seed_permissions_roles(new_course.location.course_id) # auto-enroll the course creator in the course so that "View Live" will # work. CourseEnrollment.enroll(request.user, new_course.location.course_id) _users_assign_default_role(new_course.location) return JsonResponse({'url': new_location.url_reverse("course/", "")})
def create_new_course(request): """ Create a new course. Returns the URL for the course overview page. """ if not auth.has_access(request.user, CourseCreatorRole()): raise PermissionDenied() org = request.json.get('org') number = request.json.get('number') display_name = request.json.get('display_name') run = request.json.get('run') # allow/disable unicode characters in course_id according to settings if not settings.FEATURES.get('ALLOW_UNICODE_COURSE_ID'): if _has_non_ascii_characters(org) or _has_non_ascii_characters( number) or _has_non_ascii_characters(run): return JsonResponse( { 'error': _('Special characters not allowed in organization, course number, and course run.' ) }, status=400) try: course_key = SlashSeparatedCourseKey(org, number, run) # instantiate the CourseDescriptor and then persist it # note: no system to pass if display_name is None: metadata = {} else: metadata = {'display_name': display_name} # Set a unique wiki_slug for newly created courses. To maintain active wiki_slugs for # existing xml courses this cannot be changed in CourseDescriptor. # # TODO get rid of defining wiki slug in this org/course/run specific way and reconcile # w/ xmodule.course_module.CourseDescriptor.__init__ wiki_slug = u"{0}.{1}.{2}".format(course_key.org, course_key.course, course_key.run) definition_data = {'wiki_slug': wiki_slug} # Create the course then fetch it from the modulestore # Check if role permissions group for a course named like this already exists # Important because role groups are case insensitive if CourseRole.course_group_already_exists(course_key): raise InvalidLocationError() fields = {} fields.update(definition_data) fields.update(metadata) # Creating the course raises InvalidLocationError if an existing course with this org/name is found new_course = modulestore('direct').create_course( course_key.org, course_key.offering, fields=fields, ) # can't use auth.add_users here b/c it requires request.user to already have Instructor perms in this course # however, we can assume that b/c this user had authority to create the course, the user can add themselves CourseInstructorRole(new_course.id).add_users(request.user) auth.add_users(request.user, CourseStaffRole(new_course.id), request.user) # seed the forums seed_permissions_roles(new_course.id) # auto-enroll the course creator in the course so that "View Live" will # work. CourseEnrollment.enroll(request.user, new_course.id) _users_assign_default_role(new_course.id) return JsonResponse( {'url': reverse_course_url('course_handler', new_course.id)}) except InvalidLocationError: return JsonResponse({ 'ErrMsg': _('There is already a course defined with the same ' 'organization, course number, and course run. Please ' 'change either organization or course number to be unique.'), 'OrgErrMsg': _('Please change either the organization or ' 'course number so that it is unique.'), 'CourseErrMsg': _('Please change either the organization or ' 'course number so that it is unique.'), }) except InvalidKeyError as error: return JsonResponse({ "ErrMsg": _("Unable to create course '{name}'.\n\n{err}").format( name=display_name, err=error.message) })
def test_creator_group_not_enabled(self): """ Tests that CourseCreatorRole().has_user always returns True if ENABLE_CREATOR_GROUP and DISABLE_COURSE_CREATION are both not turned on. """ self.assertTrue(user_has_role(self.user, CourseCreatorRole()))
def test_remove_user_from_group_requires_active(self): with self.assertRaises(PermissionDenied): self.admin.is_active = False remove_users(self.admin, CourseCreatorRole(), self.user)
def test_remove_user_from_group_requires_authenticated(self): with self.assertRaises(PermissionDenied): self.admin.is_authenticated = mock.Mock(return_value=False) remove_users(self.admin, CourseCreatorRole(), self.user)
def test_add_user_to_group_requires_authenticated(self): with self.assertRaises(PermissionDenied): with mock.patch('django.contrib.auth.models.User.is_authenticated' ) as mock_is_auth: mock_is_auth.return_value = False add_users(self.admin, CourseCreatorRole(), self.user)
def test_add_user_to_group_requires_authenticated(self): with self.assertRaises(PermissionDenied): self.admin.is_authenticated = False add_users(self.admin, CourseCreatorRole(), self.user)
def set_roles_for_edx_users(user, permissions, strategy): ''' This function is specific functional for open-edx platform. It create roles for edx users from sso permissions. ''' log_message = 'For User: {}, object_type {} and object_id {} there is not matched Role for Permission set: {}' global_perm = { 'Read', 'Update', 'Delete', 'Publication', 'Enroll', 'Manage(permissions)' } staff_perm = {'Read', 'Update', 'Delete', 'Publication', 'Enroll'} tester_perm = {'Read', 'Enroll'} role_ids = set(user.courseaccessrole_set.values_list('id', flat=True)) new_role_ids = [] is_global_staff = False for role in permissions: _log = False if role['obj_type'] == '*': if '*' in role['obj_perm'] or global_perm.issubset( set(role['obj_perm'])): GlobalStaff().add_users(user) is_global_staff = True elif 'Create' in role['obj_perm']: if not CourseCreatorRole().has_user(user): CourseCreatorRole().add_users(user) car = CourseAccessRole.objects.get(user=user, role=CourseCreatorRole.ROLE) new_role_ids.append(car.id) if role['obj_perm'] != '*' and global_perm != set( role['obj_perm']) and ['Create'] != role['obj_perm']: _log = True elif role['obj_type'] == 'edxorg': if '*' in role['obj_perm'] or global_perm.issubset( set(role['obj_perm'])): if not OrgInstructorRole(role['obj_id']).has_user(user): OrgInstructorRole(role['obj_id']).add_users(user) car = CourseAccessRole.objects.get( user=user, role=OrgInstructorRole(role['obj_id'])._role_name, org=role['obj_id']) new_role_ids.append(car.id) elif staff_perm.issubset(set(role['obj_perm'])): if not OrgStaffRole(role['obj_id']).has_user(user): OrgStaffRole(role['obj_id']).add_users(user) car = CourseAccessRole.objects.get( user=user, role=OrgStaffRole(role['obj_id'])._role_name, org=role['obj_id']) new_role_ids.append(car.id) elif 'Read' in role['obj_perm']: if not OrgLibraryUserRole(role['obj_id']).has_user(user): OrgLibraryUserRole(role['obj_id']).add_users(user) car = CourseAccessRole.objects.get( user=user, role=OrgLibraryUserRole.ROLE, org=role['obj_id']) new_role_ids.append(car.id) if role['obj_perm'] != '*' and global_perm != set(role['obj_perm']) and \ staff_perm != set(role['obj_perm']) and 'Read' not in role['obj_perm']: _log = True elif role['obj_type'] in ['edxcourse', 'edxlibrary']: course_key = CourseKey.from_string(role['obj_id']) if '*' in role['obj_perm'] or global_perm.issubset( set(role['obj_perm'])): if not CourseInstructorRole(course_key).has_user(user): CourseInstructorRole(course_key).add_users(user) car = CourseAccessRole.objects.get( user=user, role=CourseInstructorRole.ROLE, course_id=course_key) new_role_ids.append(car.id) elif staff_perm.issubset(set(role['obj_perm'])): if not CourseStaffRole(course_key).has_user(user): CourseStaffRole(course_key).add_users(user) car = CourseAccessRole.objects.get(user=user, role=CourseStaffRole.ROLE, course_id=course_key) new_role_ids.append(car.id) elif tester_perm.issubset(set(role['obj_perm'])): if not CourseBetaTesterRole(course_key).has_user(user): CourseBetaTesterRole(course_key).add_users(user) car = CourseAccessRole.objects.get( user=user, role=CourseBetaTesterRole.ROLE, course_id=course_key) new_role_ids.append(car.id) elif role['obj_type'] == 'edxlibrary' and 'Read' in role[ 'obj_perm']: if not LibraryUserRole(course_key).has_user(user): LibraryUserRole(course_key).add_users(user) car = CourseAccessRole.objects.get( user=user, role=CourseBetaTesterRole.ROLE, course_id=course_key) new_role_ids.append(car.id) if role['obj_perm'] != '*' and global_perm != set(role['obj_perm']) and \ staff_perm != set(role['obj_perm']) and tester_perm != set(role['obj_perm']) and 'Read' not in role['obj_perm']: _log = True elif role['obj_type'] == 'edxcourserun': course_key = CourseKey.from_string(role['obj_id']) if '*' in role['obj_perm'] or global_perm.issubset( set(role['obj_perm'])): if not CourseInstructorRole(course_key).has_user(user): CourseInstructorRole(course_key).add_users(user) car = CourseAccessRole.objects.get( user=user, role=CourseInstructorRole.ROLE, course_id=course_key) new_role_ids.append(car.id) elif staff_perm.issubset(set(role['obj_perm'])): if not CourseStaffRole(course_key).has_user(user): CourseStaffRole(course_key).add_users(user) car = CourseAccessRole.objects.get(user=user, role=CourseStaffRole.ROLE, course_id=course_key) new_role_ids.append(car.id) elif tester_perm.issubset(set(role['obj_perm'])): if not CourseBetaTesterRole(course_key).has_user(user): CourseBetaTesterRole(course_key).add_users(user) car = CourseAccessRole.objects.get( user=user, role=CourseBetaTesterRole.ROLE, course_id=course_key) new_role_ids.append(car.id) if role['obj_perm'] != '*' and global_perm != set(role['obj_perm']) and \ staff_perm != set(role['obj_perm']) and tester_perm != set(role['obj_perm']): _log = True if _log: logging.warning( log_message.format(user.id, role['obj_type'], role['obj_id'], str(role['obj_perm']))) if (not is_global_staff) and GlobalStaff().has_user(user): GlobalStaff().remove_users(user) remove_roles = role_ids - set(new_role_ids) if remove_roles: entries = CourseAccessRole.objects.filter(id__in=list(remove_roles)) entries.delete()